diff mbox series

[fortran] Fix memory leak on deallocation

Message ID 045e6de8-2720-54d4-2e3e-9f9d88f257b4@tkoenig.net
State New
Headers show
Series [fortran] Fix memory leak on deallocation | expand

Commit Message

Thomas König June 7, 2020, 2:40 p.m. UTC
Hello world,

Our finalization handling is a mess.  Really, we should get to try and get
this fixed for gcc 11.

In the meantime, here is a patch which fixes a regression I introduced
when fixing a regression with a memory leak.  The important thing
here is to realize that we do not need to finalize (and deallocate)
multiple times for the same expression and the same component
in the same namespace.  It might cause code size regressions, but
better big code than wrong code...

This is a regression all the way down to gcc 8.  OK for all affected
branches?

Regards

	Thomas

gcc/fortran/ChangeLog:

	PR fortran/94109
	* class.c (finalize_component): Return early if finalization has
	already happened for expression and component within namespace.
	* gfortran.h (gfc_was_finalized): New type.
	(gfc_namespace): Add member was_finalzed.
	(gfc_expr): Remove finalized.
	* symbol.c (gfc_free_namespace): Free was_finalized.

gcc/testsuite/ChangeLog:

	PR fortran/94109
	* gfortran.dg/finalize_34.f90: Adjust free counts.
	* gfortran.dg/finalize_36.f90: New test.

Comments

Thomas König June 12, 2020, 7:24 a.m. UTC | #1
> In the meantime, here is a patch which fixes a regression I introduced
> when fixing a regression with a memory leak.  The important thing
> here is to realize that we do not need to finalize (and deallocate)
> multiple times for the same expression and the same component
> in the same namespace.  It might cause code size regressions, but
> better big code than wrong code...
> 
> This is a regression all the way down to gcc 8.  OK for all affected
> branches?

Ping?

Unless there are any objections, I would commit this to master
on Sunday.

Regards

	Thomas
diff mbox series

Patch

diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c
index 9aa3eb7282c..b5a1edae27f 100644
--- a/gcc/fortran/class.c
+++ b/gcc/fortran/class.c
@@ -911,7 +911,7 @@  finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
   if (!comp_is_finalizable (comp))
     return;
 
-  if (comp->finalized)
+  if (expr->finalized)
     return;
 
   e = gfc_copy_expr (expr);
@@ -1002,6 +1002,7 @@  finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
 	}
       else
 	(*code) = cond;
+
     }
   else if (comp->ts.type == BT_DERIVED
 	    && comp->ts.u.derived->f2k_derived
@@ -1041,7 +1042,7 @@  finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
 			    sub_ns);
       gfc_free_expr (e);
     }
-  comp->finalized = true;
+  expr->finalized = 1;
 }
 
 
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 7094791e871..5af44847f9b 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1107,7 +1107,6 @@  typedef struct gfc_component
   struct gfc_typebound_proc *tb;
   /* When allocatable/pointer and in a coarray the associated token.  */
   tree caf_token;
-  bool finalized;
 }
 gfc_component;
 
@@ -2218,6 +2217,9 @@  typedef struct gfc_expr
   /* Set this if the expression came from expanding an array constructor.  */
   unsigned int from_constructor : 1;
 
+  /* Set this if the expression has already been finalized.  */
+  unsigned int finalized : 1;
+
   /* If an expression comes from a Hollerith constant or compile-time
      evaluation of a transfer statement, it may have a prescribed target-
      memory representation, and these cannot always be backformed from
diff --git a/gcc/testsuite/gfortran.dg/finalize_28.f90 b/gcc/testsuite/gfortran.dg/finalize_28.f90
index 597413b2dd3..f0c9665252f 100644
--- a/gcc/testsuite/gfortran.dg/finalize_28.f90
+++ b/gcc/testsuite/gfortran.dg/finalize_28.f90
@@ -21,4 +21,4 @@  contains
     integer, intent(out) :: edges(:,:)
   end subroutine coo_dump_edges
 end module coo_graphs
-! { dg-final { scan-tree-dump-times "__builtin_free" 5 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 6 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/finalize_33.f90 b/gcc/testsuite/gfortran.dg/finalize_33.f90
index 2205f9eed7f..3857e4485ee 100644
--- a/gcc/testsuite/gfortran.dg/finalize_33.f90
+++ b/gcc/testsuite/gfortran.dg/finalize_33.f90
@@ -116,4 +116,4 @@  contains
                                                ! (iii) mci_template
 end program main_ut
 ! { dg-final { scan-tree-dump-times "__builtin_malloc" 17 "original" } }
-! { dg-final { scan-tree-dump-times "__builtin_free" 19 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 20 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/finalize_34.f90 b/gcc/testsuite/gfortran.dg/finalize_34.f90
index e2f02a5c51c..fef7dac6d89 100644
--- a/gcc/testsuite/gfortran.dg/finalize_34.f90
+++ b/gcc/testsuite/gfortran.dg/finalize_34.f90
@@ -22,4 +22,4 @@  program main
   use testmodule
   type(evtlist_type), dimension(10) :: a
 end program main
-! { dg-final  { scan-tree-dump-times "__builtin_free" 8 "original" } }
+! { dg-final  { scan-tree-dump-times "__builtin_free" 12 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/finalize_35.f90 b/gcc/testsuite/gfortran.dg/finalize_35.f90
new file mode 100644
index 00000000000..66435c43ecc
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/finalize_35.f90
@@ -0,0 +1,48 @@ 
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+! PR 94361 - this left open some memory leaks.  Original test case by
+! Antony Lewis.
+
+module debug
+  private
+
+  Type TypeWithFinal
+   contains
+     FINAL :: finalizer  !No leak if this line is commented
+  end type TypeWithFinal
+
+  Type Tester
+     real, dimension(:), allocatable :: Dat
+     Type(TypeWithFinal) :: X
+  end Type Tester
+
+  Type :: TestType2
+     Type(Tester) :: T
+  end type TestType2
+  public Leaker
+contains
+
+  subroutine Leaker
+    type(TestType2) :: Test
+
+    allocate(Test%T%Dat(1000))
+  end subroutine Leaker
+
+  subroutine finalizer(this)
+    Type(TypeWithFinal) :: this
+  end subroutine finalizer
+
+end module debug
+
+
+program run
+  use debug
+  implicit none
+  integer i
+
+  do i=1, 1000
+     call Leaker()
+  end do
+
+end program run
+! { dg-final  { scan-tree-dump-times "__builtin_free\\ \\(ptr2" 2 "original" } }