Bug 55603 - [F03] Memory leak with scalar allocatable function result
[F03] Memory leak with scalar allocatable function result
Status: NEW
Product: gcc
Classification: Unclassified
Component: fortran
4.8.0
: P3 normal
: ---
Assigned To: Not yet assigned to anyone
: wrong-code
: 46487 58229 (view as bug list)
Depends on:
Blocks: 37336
  Show dependency treegraph
 
Reported: 2012-12-05 04:02 UTC by Damian Rouson
Modified: 2015-01-03 12:56 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-12-05 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Damian Rouson 2012-12-05 04:02:32 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.

Damian


$ gfortran --version
GNU Fortran (MacPorts gcc48 4.8-20121202_0) 4.8.0 20121202 (experimental)

$ cat leak.f90
  type foo
  end type
  type(foo) a
  a = bar()
contains
  function bar()
    type(foo), allocatable :: bar
    allocate(bar)
  end function
end
$ 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==
--5151-- ./a.out:
--5151-- dSYM directory is missing; consider using --dsymutil=yes
==5151==
==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==
==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==
==5151== For counts of detected and suppressed errors, rerun with: -v
==5151== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Comment 1 janus 2012-12-05 08:26:19 UTC
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.
Comment 2 Tobias Burnus 2012-12-05 10:00:09 UTC
The issue seems to only occur with scalars.

Generated code

  a = *bar ();

Expected: One uses a temporary as in

  tmp = bar ();
  a = *tmp;
  free (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).]
Comment 3 Tobias Burnus 2012-12-05 10:14:03 UTC
(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;
final_wrapper (*tmp);
free (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, "4.5.6.3 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.
Comment 4 janus 2012-12-28 16:01:57 UTC
(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).
Comment 5 Damian Rouson 2013-01-20 18:59:54 UTC
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. 

Damian
Comment 6 Tobias Burnus 2013-08-25 14:46:14 UTC
*** Bug 58229 has been marked as a duplicate of this bug. ***
Comment 7 Tobias Burnus 2013-08-25 14:47:03 UTC
*** Bug 46487 has been marked as a duplicate of this bug. ***
Comment 8 janus 2015-01-03 12:56:33 UTC
PR 60913 is closely related and contains a more complicated test case.