Bug 86481 - [OOP] Memory leak with sourced allocation
Summary: [OOP] Memory leak with sourced allocation
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 7.2.0
: P3 normal
Target Milestone: ---
Assignee: Paul Thomas
Keywords: wrong-code
Depends on:
Blocks: 86754
  Show dependency treegraph
Reported: 2018-07-11 08:37 UTC by Rich Townsend
Modified: 2019-03-30 10:53 UTC (History)
2 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2018-07-28 00:00:00

Example program showing the leak (329 bytes, text/plain)
2018-07-11 08:37 UTC, Rich Townsend

Note You need to log in before you can comment on or make changes to this bug.
Description Rich Townsend 2018-07-11 08:37:38 UTC
Created attachment 44380 [details]
Example program showing the leak

I've come across a memory leak with gfortran 7.2.0 (running on Gentoo Linux x86_64), that seems somehow to be related to nested sourced allocations (at least, that's what I've been able to determine). I attach a simple test case that demonstrates the problem. Compile this with

gfortran -O2 -g -o simple_leak simple_leak.f90

Then, running valgrind:

valgrind --leak-check=full ./simple_leak

...I get the following output:

==11555== Memcheck, a memory error detector
==11555== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11555== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11555== Command: ./simple_leak
==11555== HEAP SUMMARY:
==11555==     in use at exit: 89,600 bytes in 400 blocks
==11555==   total heap usage: 515 allocs, 115 frees, 133,468 bytes allocated
==11555== 44,800 (4,800 direct, 40,000 indirect) bytes in 100 blocks are definitely lost in loss record 4 of 4
==11555==    at 0x4C29BFD: malloc (vg_replace_malloc.c:299)
==11555==    by 0x4006CC: func_foo (simple_leak.f90:44)
==11555==    by 0x4006CC: func_bar (simple_leak.f90:33)
==11555==    by 0x4006CC: simple_leak (simple_leak.f90:23)
==11555==    by 0x4006CC: main (simple_leak.f90:22)
==11555== LEAK SUMMARY:
==11555==    definitely lost: 4,800 bytes in 100 blocks
==11555==    indirectly lost: 40,000 bytes in 100 blocks
==11555==      possibly lost: 0 bytes in 0 blocks
==11555==    still reachable: 44,800 bytes in 200 blocks
==11555==         suppressed: 0 bytes in 0 blocks
==11555== Reachable blocks (those to which a pointer was found) are not shown.
==11555== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==11555== For counts of detected and suppressed errors, rerun with: -v
==11555== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

From a bit of playing around, it seems the error may be related to the fact that I'm doing a pair of nested sourced allocations -- one allocation (in func_bar) has an expression for the SOURCE argument that involves a second sourced allocation (in func_foo).


Comment 1 Rich Townsend 2018-07-11 09:08:55 UTC
As addenda:

*) I also see the problem on gfortran 8.1

*) It doesn't seem to matter whether bar_t is a subclass of foo_t. This choice was based on the code I developed the test case for, but removing the extends(foo_t) clause from the definition of bar_t leads to the same outcome.


Comment 2 Dominique d'Humieres 2018-07-28 17:46:56 UTC
Related to pr80477, but not fixed by the patch at https://gcc.gnu.org/ml/fortran/2018-07/msg00123.html.
Comment 3 janus 2018-07-28 18:06:31 UTC
Here is the simplest reduction of the test case that I could find:

program simple_leak

  implicit none

  type :: foo_t
  end type

  class(foo_t), allocatable :: f

  allocate(f, SOURCE=func_foo())


  function func_foo () result (f)
    class(foo_t), allocatable :: f
    allocate(foo_t :: f)
  end function


It leaks a lot less, though:

==27446== HEAP SUMMARY:
==27446==     in use at exit: 2 bytes in 2 blocks
==27446==   total heap usage: 23 allocs, 21 frees, 13,562 bytes allocated
==27446== 1 bytes in 1 blocks are definitely lost in loss record 2 of 2
Comment 4 Paul Thomas 2018-08-26 13:44:01 UTC
I am just about to post a patch for this PR.

Comment 5 Paul Thomas 2018-08-28 11:36:25 UTC
Author: pault
Date: Tue Aug 28 11:35:52 2018
New Revision: 263916

URL: https://gcc.gnu.org/viewcvs?rev=263916&root=gcc&view=rev
2017-08-28  Paul Thomas  <pault@gcc.gnu.org>

	PR fortran/80477
	* trans-expr.c (gfc_conv_procedure_call): Allocatable class
	scalar results being passed to a derived type formal argument
	are finalized if possible. Otherwise, rely on existing code for
	deallocation. Make the deallocation of allocatable result
	components conditional on finalization not taking place. Make
	the freeing of data components after finalization conditional
	on the data being NULL.
	(gfc_trans_arrayfunc_assign): Change the gcc_assert to a
	condition to return NULL_TREE.
	(gfc_trans_assignment_1): If the assignment is class to class
	and the rhs expression must be finalized but the assignment
	is not marked as a polymorphic assignment, use the vptr copy
	function instead of gfc_trans_scalar_assign.

	PR fortran/86481
	* trans-expr.c (gfc_conv_expr_reference): Do not add the post
	block to the pre block if the expression is to be finalized.
	* trans-stmt.c (gfc_trans_allocate): If the expr3 must be
	finalized, load the post block into a finalization block and
	add it right at the end of the allocation block.

2017-08-28  Paul Thomas  <pault@gcc.gnu.org>

	PR fortran/80477
	* gfortran.dg/class_result_7.f90: New test.
	* gfortran.dg/class_result_8.f90: New test.
	* gfortran.dg/class_result_9.f90: New test.

	PR fortran/86481
	* gfortran.dg/allocate_with_source_25.f90: New test.

Comment 6 Martin Liška 2018-11-20 08:36:33 UTC
Paul: Can the bug be marked as resolved?
Comment 7 Paul Thomas 2019-01-26 17:24:16 UTC
Closing since it is fixed on trunk.

Thanks for the report.

Comment 8 Dominique d'Humieres 2019-03-30 10:53:21 UTC
*** Bug 89890 has been marked as a duplicate of this bug. ***