Bug 47637 - [OOP] Memory leak involving INTENT(OUT) CLASS argument w/ allocatable components
[OOP] Memory leak involving INTENT(OUT) CLASS argument w/ allocatable components
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: fortran
4.6.0
: P3 normal
: ---
Assigned To: janus
: wrong-code
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2011-02-07 22:11 UTC by Rich Townsend
Modified: 2011-02-09 16:01 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-02-08 20:14:11


Attachments
Source code plus makefile (3.06 KB, application/x-gzip)
2011-02-07 22:11 UTC, Rich Townsend
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Rich Townsend 2011-02-07 22:11:55 UTC
Created attachment 23271 [details]
Source code plus makefile

The attached test-case code (Makefile included) compiles fine with gfortran 4.6 on Mac OSX 10.6. However, when I run the code I get a significant memory leak. Valgrind reports:

==84427== LEAK SUMMARY:
==84427==    definitely lost: 38,496,000 bytes in 4,000 blocks
==84427==    indirectly lost: 0 bytes in 0 blocks
==84427==      possibly lost: 0 bytes in 0 blocks
==84427==    still reachable: 88 bytes in 1 blocks
==84427==         suppressed: 0 bytes in 0 blocks
==84427== Rerun with --leak-check=full to see details of leaked memory

The leaks are occurring with the st_l and st_r derived types in the evolve() subroutine in hydro_evolve.f90; it seems that the allocatable components of these variables are not being automatically deallocated when the recon() subroutine is called, even though the corresponding dummy arguments in recon() are declared as INTENT(out)..

If I uncomment the deallocate statements in evolve(), so that I do the deallocation 'by hand', then the memory leak is fixed. So, a workaround is possible, but this seems to be quite a fundamental bug.
Comment 1 janus 2011-02-08 20:14:11 UTC
Confirmed. Here is a shorter example with the same symptoms:


program leaky

type :: t
  integer, allocatable :: i(:)
end type

type(t) :: a

call init(a)
call init(a)

contains

  subroutine init(x)
    class(t), intent(out) :: x
    allocate(x%i(1000))
  end subroutine

end program


Note that the memory leak only occurs with a CLASS argument, not with TYPE. Also the auto-dealloc at the end of the main program works correctly, so that we only lose one of the two allocations.
Comment 2 janus 2011-02-08 22:38:15 UTC
Something like this should fix it:


Index: gcc/fortran/trans-decl.c
===================================================================
--- gcc/fortran/trans-decl.c	(revision 169891)
+++ gcc/fortran/trans-decl.c	(working copy)
@@ -3192,7 +3192,35 @@ init_intent_out_dt (gfc_symbol * proc_sym, gfc_wra
        else if (f->sym->value)
 	  gfc_init_default_dt (f->sym, &init, true);
       }
+    else if (f->sym && f->sym->attr.intent == INTENT_OUT
+	     && f->sym->ts.type == BT_CLASS
+	     && !CLASS_DATA (f->sym)->attr.class_pointer
+	     && CLASS_DATA (f->sym)->ts.u.derived->attr.alloc_comp)
+      {
+	tree decl = build_fold_indirect_ref_loc (input_location,
+						  f->sym->backend_decl);
+	tmp = CLASS_DATA (f->sym)->backend_decl;
+	tmp = fold_build3_loc (input_location, COMPONENT_REF,
+				TREE_TYPE (tmp), decl,
+				tmp, NULL_TREE);
+	tmp = build_fold_indirect_ref_loc (input_location, tmp);
+	tmp = gfc_deallocate_alloc_comp (CLASS_DATA (f->sym)->ts.u.derived,
+					  tmp,
+					  CLASS_DATA (f->sym)->as ?
+					  CLASS_DATA (f->sym)->as->rank : 0);
 
+	if (f->sym->attr.optional
+	    || f->sym->ns->proc_name->attr.entry_master)
+	  {
+	    present = gfc_conv_expr_present (f->sym);
+	    tmp = build3_loc (input_location, COND_EXPR, TREE_TYPE (tmp),
+			      present, tmp,
+			      build_empty_stmt (input_location));
+	  }
+
+	gfc_add_expr_to_block (&init, tmp);
+      }
+
   gfc_add_init_cleanup (block, gfc_finish_block (&init), NULL_TREE);
 }
 


This gets rid of the memleaks in both comment #0 and comment #1 for me, but is not regtested yet.
Comment 3 janus 2011-02-09 09:56:31 UTC
The patch in comment #2 regtests cleanly on x86_64-unknown-linux-gnu, without any failures.
Comment 4 Tobias Burnus 2011-02-09 14:02:58 UTC
See bug 46321 regarding the required full solution for polymophic allocatables.

Special case solution, cf. approved patch at http://gcc.gnu.org/ml/fortran/2011-02/msg00067.html
Comment 5 janus 2011-02-09 15:58:11 UTC
Author: janus
Date: Wed Feb  9 15:58:05 2011
New Revision: 169978

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=169978
Log:
2011-02-09  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/47637
	* trans-decl.c (init_intent_out_dt): Handle CLASS arguments.


2011-02-09  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/47637
	* gfortran.dg/auto_dealloc_2.f90: New.

Added:
    trunk/gcc/testsuite/gfortran.dg/auto_dealloc_2.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/trans-decl.c
    trunk/gcc/testsuite/ChangeLog
Comment 6 janus 2011-02-09 16:01:04 UTC
Fixed with r169978. Thanks for the report, Rich!

Note that further memory leaks are to expected for cases where the dynamic type is different from the declared type (and has additional allocatable components), cf. PR 46321.