Summary: | [OOP] Memory leak involving INTENT(OUT) CLASS argument w/ allocatable components | ||
---|---|---|---|
Product: | gcc | Reporter: | Rich Townsend <townsend> |
Component: | fortran | Assignee: | janus |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | burnus, janus |
Priority: | P3 | Keywords: | wrong-code |
Version: | 4.6.0 | ||
Target Milestone: | 4.6.0 | ||
Host: | Target: | ||
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | 2011-02-08 20:14:11 | |
Attachments: | Source code plus makefile |
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. 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. The patch in comment #2 regtests cleanly on x86_64-unknown-linux-gnu, without any failures. 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 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 |
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.