https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90072
Bug ID: 90072
Summary: Polymorphic Dispatch to Polymophic Return Type Memory
Leak
Product: gcc
Version: 8.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: fortran
Assignee: unassigned at gcc dot gnu.org
Reporter: brichardson at structint dot com
Target Milestone: ---
It appears that trying to do polymorphic dispatch to a function that has a
polymorphic return type leads to a memory leak. But, by using a select type
construct, the memory leak doesn't occur.
The following program and module demonstrate the problem.
program dispatch_memory_leak
implicit none
call run()
contains
subroutine run()
use types, only: base_returned, base_called, first_extended
class(base_called), allocatable :: to_call
class(base_returned), allocatable :: to_get
allocate(to_call, source = first_extended())
allocate(to_get, source = to_call%get()) ! This is a memory leak
deallocate(to_get)
select type(to_call)
type is (first_extended)
allocate(to_get, source = to_call%get()) ! This got fixed
end select
end subroutine run
end program dispatch_memory_leak
module types
implicit none
type, abstract :: base_returned
end type base_returned
type, extends(base_returned) :: first_returned
end type first_returned
type, extends(base_returned) :: second_returned
end type second_returned
type, abstract :: base_called
contains
procedure(get_), deferred :: get
end type base_called
type, extends(base_called) :: first_extended
contains
procedure :: get => getFirst
end type first_extended
type, extends(base_called) :: second_extended
contains
procedure :: get => getSecond
end type second_extended
abstract interface
function get_(self) result(returned)
import base_called
import base_returned
class(base_called), intent(in) :: self
class(base_returned), allocatable :: returned
end function get_
end interface
contains
function getFirst(self) result(returned)
class(first_extended), intent(in) :: self
class(base_returned), allocatable :: returned
allocate(returned, source = first_returned())
end function getFirst
function getSecond(self) result(returned)
class(second_extended), intent(in) :: self
class(base_returned), allocatable :: returned
allocate(returned, source = second_returned())
end function getSecond
end module types
$ gfortran -c -g types.f90 -o types.o
$ gfortran -c -g dispatch_memory_leak.f90 -o dispatch_memory_leak.o
$ gfortran -g types.o dispatch_memory_leak.o -o dispatch_memory_leak
$ valgrind --leak-check=full ./dispatch_memory_leak
==8261== Memcheck, a memory error detector
==8261== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8261== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==8261== Command: ./dispatch_memory_leak
==8261==
==8261==
==8261== HEAP SUMMARY:
==8261== in use at exit: 2 bytes in 2 blocks
==8261== total heap usage: 26 allocs, 24 frees, 13,525 bytes allocated
==8261==
==8261== 1 bytes in 1 blocks are definitely lost in loss record 1 of 2
==8261== at 0x483777F: malloc (vg_replace_malloc.c:299)
==8261== by 0x1092EE: __types_MOD_getfirst (types.f90:41)
==8261== by 0x109446: run.3770 (dispatch_memory_leak.f90:13)
==8261== by 0x10973D: MAIN__ (dispatch_memory_leak.f90:4)
==8261== by 0x109789: main (dispatch_memory_leak.f90:4)
==8261==
==8261== 1 bytes in 1 blocks are definitely lost in loss record 2 of 2
==8261== at 0x483777F: malloc (vg_replace_malloc.c:299)
==8261== by 0x1092EE: __types_MOD_getfirst (types.f90:41)
==8261== by 0x10959A: run.3770 (dispatch_memory_leak.f90:18)
==8261== by 0x10973D: MAIN__ (dispatch_memory_leak.f90:4)
==8261== by 0x109789: main (dispatch_memory_leak.f90:4)
==8261==
==8261== LEAK SUMMARY:
==8261== definitely lost: 2 bytes in 2 blocks
==8261== indirectly lost: 0 bytes in 0 blocks
==8261== possibly lost: 0 bytes in 0 blocks
==8261== still reachable: 0 bytes in 0 blocks
==8261== suppressed: 0 bytes in 0 blocks
==8261==
==8261== For counts of detected and suppressed errors, rerun with: -v
==8261== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Note that the leak that occurs inside the select type construct here appears to
have been fixed in the version of 9.0 that we are running at work. (That
version is from some time in September).
I'm running the official version from Arch Linux.