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.

Reply via email to