https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106750
Bug ID: 106750 Summary: Memory leak calling section of derived type containing `allocatable` entries Product: gcc Version: 9.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: fortran Assignee: unassigned at gcc dot gnu.org Reporter: federico.perini at gmail dot com Target Milestone: --- Running a large CFD program I've found a memory leak gfortran 9.2.0 (sorry: unable to test other versions on that system) that occurs when: - derived type contains `allocatable` entries - a chunk of an array of the aforementioned derived type is used as input to a function - happens whether or not the derived type contains a final routine Here's a minimal working example: module tmod implicit none type, public :: t integer :: i,j,k integer, allocatable :: a(:) ! No leaks if these are fixed-size integer, allocatable :: b(:) ! No leaks if these are fixed-size ! integer :: a(3),b(20) ! uncomment to test fixed-size end type t contains integer function do_with_array(ts) result(l) type(t), intent(in) :: ts(2) integer :: i(2),j(2),k(2) i = max(ts(:)%i,0) j = max(ts(:)%j,0) k = max(ts(:)%k,0) l = sum(i+j+k) end function integer function do_with_scalars(t1,t2) result(l) type(t), intent(in) :: t1,t2 integer :: i(2),j(2),k(2) i(1) = max(t1%i,0); i(2) = max(t2%i,0) j(1) = max(t1%j,0); j(2) = max(t2%j,0) k(1) = max(t1%k,0); k(2) = max(t2%k,0) l = sum(i+j+k) end function end module tmod program test use tmod implicit none integer, parameter :: n = 1000 type(t), allocatable :: ts(:) integer :: j(n),choose(2),i,k(n) real :: x(2) ! Initialize with anything allocate(ts(n)); do i=1,n ts(i) = t(i,2*i,3*i,[(i,i=1,3)],[(2*i,i=1,20)]) end do ! Do several calls do i=1,n call random_number(x); choose = ceiling(x*n) ! [leak #1] j(i) = do_with_array(ts(choose)) ! [#1] MEMORY LEAK ! no leak ever k(i) = do_with_scalars(ts(choose(1)),ts(choose(2))) end do print *, 'sum=',sum(j) ! [leak #2] happens if ts is not deallocated. Shouldn't a program work like a ! subroutine, and deallocate everything that's going out of scope? deallocate(ts) end program test The results with valgrind are: [perini1@srv0 ~]$ valgrind --tool=memcheck --leak-check=yes --track-origins=yes ./a.out ==49159== Memcheck, a memory error detector ==49159== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==49159== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==49159== Command: ./a.out ==49159== sum= 5960916 ==49159== ==49159== HEAP SUMMARY: ==49159== in use at exit: 197,026 bytes in 4,001 blocks ==49159== total heap usage: 6,023 allocs, 2,022 frees, 446,610 bytes allocated ==49159== ==49159== 24,000 bytes in 2,000 blocks are definitely lost in loss record 2 of 3 ==49159== at 0x4C28A2E: malloc (vg_replace_malloc.c:270) ==49159== by 0x402204: MAIN__ (test_leak.f90:55) ==49159== by 0x4026C9: main (test_leak.f90:36) ==49159== ==49159== 160,000 bytes in 2,000 blocks are definitely lost in loss record 3 of 3 ==49159== at 0x4C28A2E: malloc (vg_replace_malloc.c:270) ==49159== by 0x402337: MAIN__ (test_leak.f90:55) ==49159== by 0x4026C9: main (test_leak.f90:36) ==49159== ==49159== LEAK SUMMARY: ==49159== definitely lost: 184,000 bytes in 4,000 blocks ==49159== indirectly lost: 0 bytes in 0 blocks ==49159== possibly lost: 0 bytes in 0 blocks ==49159== still reachable: 13,026 bytes in 1 blocks ==49159== suppressed: 0 bytes in 0 blocks ==49159== Reachable blocks (those to which a pointer was found) are not shown. ==49159== To see them, rerun with: --leak-check=full --show-reachable=yes ==49159== ==49159== For counts of detected and suppressed errors, rerun with: -v ==49159== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 8 from 6) Profiling timer expired