This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gfortran memory leak? Was:Re: PRIVATE statement in UDDT causes memory leak with ALLOCATABLE components?


Hello,

I posted a request for info on clf regarding this issue, but decided to send a followup to the gfortran list.... hope folks don't mind.

I have a test program (listed at the end of this post) that seems to indicate something funky going on with gfortran when:
1) a derived type allocatable component is itself a derived type with
allocatable components
2) my destroy functions rely on the INTENT(OUT) attribute to handle the
deallocations, and
3) the structure definitions contain PRIVATE access statements.
Results for gfortran (and g95 and pgf95) are shown below when I run the executable through valgrind.


g95 and pgf95 have no memory leaks (correctly, I believe), while gfortran does.

Interestingly, the commenting out of the PRIVATE statement in the definition for s_type doesn't make the gfortran memory leak disappear, but it does seem to make it smaller. Similarly if just the p_type PRIVATE statement is commented out. Commenting out *both* private statements *does* make the memory leak disappear.

Is this a gfortran bug, or is there something I'm not grokking about TR15581 derived type allocatable components when the structure definition contains a PRIVATE statement? gfortran does support TR15581, right?

Any comments, suggestions, fixes (for my code), or workarounds appreciated.

Regards,

paulv



Compiler info:
==============
$ : gfortran --version
GNU Fortran (GCC) 4.4.0 20090219 (experimental) [trunk revision 144294]

$ : g95 --version
G95 (GCC 4.0.3 (g95 0.92!) Jan  7 2009)

$ : pgf95 -V
pgf95 7.2-4 32-bit target on x86 Linux -tp core2



Kernel and glibc info
=====================
 Kernel version:
2.6.18-128.1.16.el5PAE

 glibc version:
Name        : glibc
Version     : 2.5
Release     : 34
Vendor      : Red Hat, Inc.
Source RPM  : glibc-2.5-34.src.rpm



gfortran results (with PRIVATE statement in s_type and p_type definition):
==========================================================================
$ : gfortran -pg test_pa.f90
$ : valgrind --leak-check=full a.out
==514== Memcheck, a memory error detector.
==514==
2 2
2 2
2 2
2 2
==514==
==514== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 18 from 1)
==514== malloc/free: in use at exit: 3,948 bytes in 14 blocks.
==514== malloc/free: 28 allocs, 14 frees, 30,421 bytes allocated.
==514== For counts of detected errors, rerun with: -v
==514== searching for pointers to 14 not-freed blocks.
==514== checked 74,856 bytes.
==514==
==514== 32 bytes in 4 blocks are definitely lost in loss record 1 of 4
==514== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==514== by 0x80489CA: __p_define_MOD_alloc_p (in a.out)
==514== by 0x8048E32: __s_define_MOD_alloc_s (in a.out)
==514== by 0x8048B8B: __s_define_MOD_copy_s (in a.out)
==514== by 0x8049003: MAIN__ (in a.out)
==514== by 0x804906A: main (fmain.c:21)
==514==
==514==
==514== 216 (168 direct, 48 indirect) bytes in 3 blocks are definitely lost in loss record 3 of 4
==514== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==514== by 0x8048CFC: __s_define_MOD_alloc_s (in a.out)
==514== by 0x8048FBF: MAIN__ (in a.out)
==514== by 0x804906A: main (fmain.c:21)
==514==
==514== LEAK SUMMARY:
==514== definitely lost: 200 bytes in 7 blocks.
==514== indirectly lost: 48 bytes in 6 blocks.
==514== possibly lost: 0 bytes in 0 blocks.
==514== still reachable: 3,700 bytes in 1 blocks.
==514== suppressed: 0 bytes in 0 blocks.
==514== Reachable blocks (those to which a pointer was found) are not shown.
==514== To see them, rerun with: --show-reachable=yes



gfortran results (without PRIVATE statement in s_type definition): ================================================================== $ : gfortran -pg test_pa.f90 $ : valgrind --leak-check=full a.out ==535== Memcheck, a memory error detector. ==535== 2 2 2 2 2 2 2 2 ==535== ==535== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 18 from 1) ==535== malloc/free: in use at exit: 4,220 bytes in 11 blocks. ==535== malloc/free: 28 allocs, 17 frees, 30,861 bytes allocated. ==535== For counts of detected errors, rerun with: -v ==535== searching for pointers to 11 not-freed blocks. ==535== checked 75,336 bytes. ==535== ==535== 80 bytes in 10 blocks are definitely lost in loss record 1 of 2 ==535== at 0x40053C0: malloc (vg_replace_malloc.c:149) ==535== by 0x80489FA: __p_define_MOD_alloc_p (in a.out) ==535== by 0x8048E3D: __s_define_MOD_alloc_s (in a.out) ==535== by 0x80490ED: MAIN__ (in a.out) ==535== by 0x80491DA: main (fmain.c:21) ==535== ==535== LEAK SUMMARY: ==535== definitely lost: 80 bytes in 10 blocks. ==535== possibly lost: 0 bytes in 0 blocks. ==535== still reachable: 4,140 bytes in 1 blocks. ==535== suppressed: 0 bytes in 0 blocks. ==535== Reachable blocks (those to which a pointer was found) are not shown. ==535== To see them, rerun with: --show-reachable=yes


gfortran results (without PRIVATE statement in either s_type or p_type definition): =================================================================================== $ : gfortran -pg test_pa.f90 $ : valgrind --leak-check=full a.out ==827== Memcheck, a memory error detector. ==827== 2 2 2 2 2 2 2 2 ==827== ==827== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 18 from 1) ==827== malloc/free: in use at exit: 5,816 bytes in 1 blocks. ==827== malloc/free: 28 allocs, 27 frees, 32,537 bytes allocated. ==827== For counts of detected errors, rerun with: -v ==827== searching for pointers to 1 not-freed blocks. ==827== checked 77,012 bytes. ==827== ==827== LEAK SUMMARY: ==827== definitely lost: 0 bytes in 0 blocks. ==827== possibly lost: 0 bytes in 0 blocks. ==827== still reachable: 5,816 bytes in 1 blocks. ==827== suppressed: 0 bytes in 0 blocks. ==827== Reachable blocks (those to which a pointer was found) are not shown. ==827== To see them, rerun with: --show-reachable=yes



g95 results (including both PRIVATE statements):
================================================
$ : g95 -pg test_pa.f90
$ : valgrind --leak-check=full a.out
==434== Memcheck, a memory error detector.
==434==
 2 2
 2 2
 2 2
 2 2
==434==
==434== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 14 from 1)
==434== malloc/free: in use at exit: 168,654 bytes in 1 blocks.
==434== malloc/free: 21 allocs, 20 frees, 221,050 bytes allocated.
==434== For counts of detected errors, rerun with: -v
==434== searching for pointers to 1 not-freed blocks.
==434== checked 272,616 bytes.
==434==
==434== LEAK SUMMARY:
==434==    definitely lost: 0 bytes in 0 blocks.
==434==      possibly lost: 0 bytes in 0 blocks.
==434==    still reachable: 168,654 bytes in 1 blocks.
==434==         suppressed: 0 bytes in 0 blocks.
==434== Reachable blocks (those to which a pointer was found) are not shown.
==434== To see them, rerun with: --show-reachable=yes


pgf95 results (including both private statements): ================================================== $ : pgf95 -pg test_pa.f90 $ : valgrind --leak-check=full a.out ==452== Memcheck, a memory error detector. ==452== 2 2 2 2 2 2 2 2 ==452== ==452== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 18 from 1) ==452== malloc/free: in use at exit: 643,650 bytes in 18 blocks. ==452== malloc/free: 20 allocs, 2 frees, 644,394 bytes allocated. ==452== For counts of detected errors, rerun with: -v ==452== searching for pointers to 18 not-freed blocks. ==452== checked 745,568 bytes. ==452== ==452== LEAK SUMMARY: ==452== definitely lost: 0 bytes in 0 blocks. ==452== possibly lost: 0 bytes in 0 blocks. ==452== still reachable: 643,650 bytes in 18 blocks. ==452== suppressed: 0 bytes in 0 blocks. ==452== Reachable blocks (those to which a pointer was found) are not shown. ==452== To see them, rerun with: --show-reachable=yes


The test program is:


<--------------------------->
<-----begin test_pa.f90----->

! Module 1
! ========
module p_define
  implicit none

  ! Derived type definition
  type :: p_type
    private
    integer :: n
    integer, allocatable :: x(:)
  end type

contains

  ! Module subprogram to inspect component
  subroutine inspect_p(p)
    type(p_type), intent(in) :: p
    print *, p%x
  end subroutine inspect_p


! Module subprogram to set component to a value subroutine set_p(val,p) integer, intent(in) :: val type(p_type), intent(in out) :: p p%x = val end subroutine set_p


! Module subprogram to destroy component subroutine destroy_p(p) type(p_type), intent(out) :: p p%n = 0 end subroutine destroy_p


! Module subprogram to allocate component subroutine alloc_p(n,p) integer, intent(in) :: n type(p_type), intent(out) :: p allocate(p%x(n)) p%n = n end subroutine alloc_p


! Module subprogram to do a deep copy subroutine copy_p(p_in,p_out) type(p_type), intent(in) :: p_in type(p_type), intent(out) :: p_out call alloc_p(p_in%n, p_out) p_out%x = p_in%x end subroutine copy_p

end module p_define


! Module 2 ! ======== module s_define use p_define implicit none

  ! Derived type definition
  type :: s_type
    private
    integer :: n
    type(p_type), allocatable :: y(:)
  end type

contains

  ! Module subprogram to inspect component
  subroutine inspect_s(s)
    type(s_type), intent(in) :: s
    integer :: i
    do i = 1, s%n
      call inspect_p(s%y(i))
    end do
  end subroutine inspect_s


! Module subprogram to set component to a value subroutine set_s(val,s) integer, intent(in) :: val type(s_type), intent(in out) :: s integer :: i do i = 1, s%n call set_p(val,s%y(i)) end do end subroutine set_s


! Module subprogram to destroy component subroutine destroy_s(s) type(s_type), intent(out) :: s s%n = 0 end subroutine destroy_s


! Module subprogram to allocate component subroutine alloc_s(n,s) integer, intent(in) :: n type(s_type), intent(out) :: s integer :: i allocate(s%y(n)) do i = 1, n call alloc_p(n,s%y(i)) end do s%n = n end subroutine alloc_s


! Module subprogram to do a deep copy subroutine copy_s(s_in,s_out) type(s_type), intent(in) :: s_in type(s_type), intent(out) :: s_out integer :: i call alloc_s(s_in%n, s_out) do i = 1, s_in%n call copy_p(s_in%y(i),s_out%y(i)) end do end subroutine copy_s

end module s_define


! Test program ! ============ program test_alloc use s_define implicit none

  ! Parameters
  integer, parameter :: N = 2

  ! Local variables
  integer :: i
  type(s_type) :: s, s_copy

  ! Allocate, assign value, and inspect s
  call alloc_s(N,s)
  call set_s(N,s)
  call inspect_s(s)

  ! Call the copy routine more than once
  do i = 1, N
    call copy_s(s, s_copy)
  end do

  ! Have a look at s_copy
  call inspect_s(s_copy)

  ! Destroy it
  call destroy_s(s)
  call destroy_s(s_copy)

end program test_alloc

<-----end test_pa.f90----->
<------------------------->


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]