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.