This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
gfortran memory leak? Was:Re: PRIVATE statement in UDDT causes memory leak with ALLOCATABLE components?
- From: Paul van Delst <Paul dot Vandelst at noaa dot gov>
- To: gfortran mailing list <fortran at gcc dot gnu dot org>
- Date: Wed, 29 Jul 2009 18:22:23 -0400
- Subject: gfortran memory leak? Was:Re: PRIVATE statement in UDDT causes memory leak with ALLOCATABLE components?
- References: <h4nqbs$jel$1@news.woc.noaa.gov>
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----->
<------------------------->