GCC Bugzilla – Bug 55603
[F03] Memory leak with scalar allocatable function result
Last modified: 2013-08-26 11:33:45 UTC
valgrind reports a memory leak in the code below. FY, this is a greatly simplified version of the actual use case. In the intended use case, the "bar" procedure is type-bound and is invoked via a type-bound generic operator that appears in a longer expression composed of various user-defined operators.
$ gfortran --version
GNU Fortran (MacPorts gcc48 4.8-20121202_0) 4.8.0 20121202 (experimental)
$ cat leak.f90
a = bar()
type(foo), allocatable :: bar
$ gfortran leak.f90
$ valgrind ./a.out
==5151== Memcheck, a memory error detector
==5151== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5151== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5151== Command: ./a.out
--5151-- dSYM directory is missing; consider using --dsymutil=yes
==5151== HEAP SUMMARY:
==5151== in use at exit: 1,998 bytes in 33 blocks
==5151== total heap usage: 49 allocs, 16 frees, 5,706 bytes allocated
==5151== LEAK SUMMARY:
==5151== definitely lost: 1 bytes in 1 blocks
==5151== indirectly lost: 0 bytes in 0 blocks
==5151== possibly lost: 0 bytes in 0 blocks
==5151== still reachable: 1,997 bytes in 32 blocks
==5151== suppressed: 0 bytes in 0 blocks
==5151== Rerun with --leak-check=full to see details of leaked memory
==5151== For counts of detected and suppressed errors, rerun with: -v
==5151== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
The problem seems to be that we fail to do auto-deallocation of the function result (after the assignment). One should check the standard, if and where this is actually demanded.
Btw, this will also be important for the future FINAL implementation.
The issue seems to only occur with scalars.
a = *bar ();
Expected: One uses a temporary as in
tmp = bar ();
a = *tmp;
The same issue occurs with reallocate LHS, were also a temporary should be used.
[Check that the allocation/freeing is properly done for variables with length type parameter (currently only deferred-length CHARACTER strings).]
(In reply to comment #1)
> The problem seems to be that we fail to do auto-deallocation of the function
> result (after the assignment). One should check the standard, if and where this
> is actually demanded.
Nowhere. It only falls into the category "quality of implementation". But a reasonable place would be after the place where finalization would occur.
> Btw, this will also be important for the future FINAL implementation.
Yes, after the function has evaluated, its result has to be finalized. I think it should be as following:
tmp = bar();
final_wrapper (a); ! must be after "bar()"
a = *tmp;
With an allocatable LHS it gets messier due to the length type parameter (and shape). In addition, it seems as if one had always to finalize the LHS in an intrinsic assignment while the (re)allocation is only allowed if the shape doesn't match.
From F2008, "18.104.22.168 When finalization occurs":
"If an executable construct references a function, the result is finalized after execution of the innermost executable construct containing the reference."
"When an intrinsic assignment statement is executed, the variable is finalized after evaluation of expr and before the definition of the variable."
By the way, the latter implies that a temporary variable has to be used if there is a finalizer and the RHS doesn't return a pointer/allocatable. Otherwise one had to finalize the LHS before evaluating the RHS expr.
(In reply to comment #2)
> The issue seems to only occur with scalars.
Right. When using an array in Damian's test case, a temporary is generated by calling gfc_trans_create_temp_array from gfc_conv_procedure_call (trans-expr.c:4979).
Hi Janus and Tobias,
We're moving toward an internal release of the open-source package that exposed this bug. Any chance of this being fixed in the near future? The lead developer Karla Morris is cc'd on this.
*** Bug 58229 has been marked as a duplicate of this bug. ***
*** Bug 46487 has been marked as a duplicate of this bug. ***