The attached code produces an error at runtime: System: Linux 2.6.27-gentoo-r8 x86_64 AMD Turion(tm) 64 Mobile Technology ML-32 AuthenticAMD GNU/Linux $ gfortran bug.f90 -o bug $ ./bug *** glibc detected *** ./bug: double free or corruption (fasttop): 0x000000000060a5b0 *** ======= Backtrace: ========= /lib/libc.so.6[0x7f516d97a468] /lib/libc.so.6(cfree+0x76)[0x7f516d97bfa6] ./bug[0x40272a] ./bug[0x40283c] /lib/libc.so.6(__libc_start_main+0xe6)[0x7f516d9255c6] ./bug[0x4007b9] [...] Aborted module mod_all implicit none public :: & t2, new2, operator(+) private type t1 integer :: n1 integer, allocatable :: d1(:) end type t1 type t2 integer :: n2 type(t1), allocatable :: d2(:) end type t2 interface operator(+) module procedure add end interface interface new2 module procedure new2, new2_2 end interface contains !----------------------------------------------------------------------- pure function new1(d1) result(m) integer, intent(in) :: d1(:) type(t1) :: m m%n1 = size(d1) allocate(m%d1(m%n1)) m%d1 = d1 end function new1 !----------------------------------------------------------------------- pure function new2(d2) result(p) type(t1), intent(in) :: d2(:) type(t2) :: p p%n2 = size(d2) allocate(p%d2(p%n2)) p%d2 = d2 end function new2 !----------------------------------------------------------------------- pure function new2_2() result(p) type(t2) :: p p = new2( (/ new1((/1,1/)) /) ) end function new2_2 !----------------------------------------------------------------------- elemental function add(p1,p2) result(p) type(t2), intent(in) :: p1,p2 type(t2) :: p p = new2((/ p1%d2 , p2%d2 /)) end function add !----------------------------------------------------------------------- end module mod_all !----------------------------------------------------------------------- program a_main use mod_all type(t2) :: q(3) q(1) = new2() q(2) = new2() q(3) = q(2) + q(1) end program a_main
CONFIRM - happens with 4.2/4.3/4.4/4.5. ==13529== Invalid read of size 8 ==13529== at 0x400F2A: __mod_all_MOD_add (in /dev/shm/a.out) ==13529== Address 0x58d56c8 is 8 bytes inside a block of size 112 free'd ==13529== at 0x4C23EEE: free (vg_replace_malloc.c:323) ==13529== by 0x400EB8: __mod_all_MOD_add (in /dev/shm/a.out)
*** This bug has been marked as a duplicate of 41777 ***
(In reply to comment #2) > > *** This bug has been marked as a duplicate of 41777 *** > Sorry! I hit something accidentally on my keyboard, I didn't mean marking this bug as a duplicate at all... Apologies!
Reduced testcase: type t1 integer, allocatable :: d1(:) end type t1 type t2 type(t1), allocatable :: d2(:) end type t2 type(t2) :: a, b a = new2( (/ new1((/1,1/)) /) ) b = new2( (/ a%d2 , a%d2 /) ) contains pure type(t1) function new1(d1) integer, intent(in) :: d1(:) allocate(new1%d1(size(d1))) new1%d1 = d1 end function pure type(t2) function new2(d2) type(t1), intent(in) :: d2(:) allocate(new2%d2(size(d2))) new2%d2 = d2 end function end The dump still has about 800 lines - somewhat hard to tell what's going on. Adding PaulT as CC.
Further reduced test case: type t integer, allocatable :: d(:) end type type(t), allocatable :: a(:) allocate(a(2)) call sub( (/ a /) ) contains subroutine sub(b) type(t) :: b(:) end subroutine end The dump still has more than 200 lines and five __builtin_free's.
I had better add this to the list! Paul
(In reply to comment #5) > Further reduced test case: > > > type t > integer, allocatable :: d(:) > end type > type(t), allocatable :: a(:) > > allocate(a(2)) > call sub( (/ a /) ) > > contains > > subroutine sub(b) > type(t) :: b(:) > end subroutine > > end > > > The dump still has more than 200 lines and five __builtin_free's. > Not sure if this is correct or useful, since I don't know the gfortran internals at all, but anyway, mostly out of curiosity: my impression is that the problem is in the lines 187-222 of the -fdump-tree-original output file. More precisely (starting with line 186): sub (&atmp.6); Here we free atmp.3.data (without worrying about the allocation status of the elements) { void * D.1574; D.1574 = (void *) atmp.3.data; if (D.1574 != 0B) { __builtin_free (D.1574); } } Here we free atmp.6.data (again, without worrying about the allocation status of the elements) { void * D.1593; D.1593 = (void *) atmp.6.data; if (D.1593 != 0B) { __builtin_free (D.1593); } } Now we look at the elements of atmp.6.data to check whether we have to free them too. It seems to the me that this block should be moved before the previous one (or eliminated at all, as it is done for atmp.3.data) if ((struct t[0:] * restrict) atmp.6.data != 0B) { D.1596 = (atmp.6.dim[0].ubound - atmp.6.dim[0].lbound) + 1; D.1597 = atmp.6.dim[0].stride * D.1596; D.1598 = D.1597 + -1; S.8 = 0; while (1) { if (S.8 > D.1598) goto L.5; Here we access memory that has already been freed if ((*(struct t[0:] * restrict) atmp.6.data)[S.8].d.data != 0B) { __builtin_free ((void *) (*(struct t[0:] * restrict) atmp.6.data)[S.8].d.data); } (*(struct t[0:] * restrict) atmp.6.data)[S.8].d.data = 0B; S.8 = S.8 + 1; } L.5:; }
I hit this bug, too, it seems. My reduced test-case: PROGRAM analysis IMPLICIT NONE TYPE numlist REAL, ALLOCATABLE :: nums(:) END TYPE numlist TYPE(numlist) :: lines ALLOCATE (lines%nums(1)) CALL test ((/ lines /)) CONTAINS SUBROUTINE test (vec) TYPE(numlist), INTENT(IN) :: vec(:) END SUbROUTINE test END PROGRAM analysis This produces 126 lines of -fdump-tree-original, so I hope it may help here as being "simpler" than the one posted by Janus (it seems).
I just noticed that using -Warray-temporaries gives the warning twice. For the test in comment #8, I get [macbook] f90/bug% gfc -Warray-temporaries -fcheck=all pr40850_3.f90 pr40850_3.f90:11.13: CALL test ((/ lines /)) 1 Warning: Creating array temporary at (1) pr40850_3.f90:11.13: CALL test ((/ lines /)) 1 Warning: Creating array temporary at (1) [macbook] f90/bug% a.out a.out(35149) malloc: *** error for object 0x100201010: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug Abort
This looks like a dupe of the nested constructor case of #38319?!
Mikael's patch for comment 5: http://gcc.gnu.org/ml/fortran/2011-02/msg00208.html It does not fix comment 8; I don't know whether it fixes comment 0 or comment 4.
(In reply to comment #11) > I don't know whether it fixes comment 0 or comment 4 > Sorry, I forgot to precise. It fixes neither. More precisely for comments 0 and 4, it does fix a read of freed memory: ==82785== Invalid read of size 8 ==82785== at 0x400F21: __mod_all_MOD_add (in /usr/home/mik/gfortran/pr40850/comment_0) ==82785== by 0x4023D9: MAIN__ (in /usr/home/mik/gfortran/pr40850/comment_0) ==82785== by 0x402703: main (in /usr/home/mik/gfortran/pr40850/comment_0) ==82785== Address 0x14be678 is 8 bytes inside a block of size 112 free'd but doesn't fix a double free affecting comments 0, 4 and 8: ==82785== Invalid free() / delete / delete[] ==82785== at 0x25A37E: free (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==82785== by 0x402609: MAIN__ (in /usr/home/mik/gfortran/pr40850/comment_0) ==82785== by 0x402703: main (in /usr/home/mik/gfortran/pr40850/comment_0) ==82785== Address 0x14be3d0 is 0 bytes inside a block of size 8 free'd Comment 8 is not affected by the invalid read as the containing entity is not allocatable, hence not explicitly freed at the end. Thus, components release can't happen before containing entity's release. For the remaining double free, the temporary for the array constructor is filled using simple copies, and thus has components pointing to the original array. Those components are freed by the temporary array cleanup, and again during the final release of all allocatables. One could fix it by not freeing the temporary's components (no deep/nested free), but I have the feeling (haven't completely made my mind about it) that the proper fix, in the general case, is to create nested temporaries and do deep copies. And yes, that would be horribly expensive :-(.
Comment 5 is not affected by the double free as the allocatable components are never allocated during the program, only the containing entity is.
Author: mikael Date: Wed Feb 23 22:38:27 2011 New Revision: 170445 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=170445 Log: 2011-02-23 Mikael Morin <mikael@gcc.gnu.org> PR fortran/40850 * trans.c (gfc_prepend_expr_to_block): New function. * trans.h (gfc_prepend_expr_to_block): Declare. * trans-array.c (gfc_conv_array_parameter): Replace gfc_add_expr_to_block with gfc_prepend_expr_to_block. 2011-02-23 Mikael Morin <mikael@gcc.gnu.org> PR fortran/40850 * gfortran.dg/nested_allocatables_1.f90: New. Added: trunk/gcc/testsuite/gfortran.dg/nested_allocatables_1.f90 Modified: trunk/gcc/fortran/ChangeLog trunk/gcc/fortran/trans-array.c trunk/gcc/fortran/trans.c trunk/gcc/fortran/trans.h trunk/gcc/testsuite/ChangeLog
All test cases given here (comment 0, 4, 5 and 8) work with gfortran 4.6.3 and above. I assume we can close this PR?
I found that the following nested deallocation program still fails in 4.6.3. Sorry it's so long, I don't have time to think about how to shorten it right now. It compiles and runs without error with ifort 12.1.4 20120410, and I didn't try it with 4.7. $ gfortran --version GNU Fortran (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 ... $ uname -a Linux hostname 3.2.0-24-generic #39-Ubuntu SMP Mon May 21 16:52:17 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux $ gfortran testdealloc.F90 $ ./a.out *** glibc detected *** ./a.out: double free or corruption (top): 0x0000000001edb0a0 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x7e626)[0x7fadbf3b1626] ./a.out[0x400fa7] ./a.out[0x401029] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fadbf35476d] ./a.out[0x400709] ======= Memory map: ======== 00400000-00402000 r-xp 00000000 08:05 132394 /home/barker/sandbox/a.out 00601000-00602000 r--p 00001000 08:05 132394 /home/barker/sandbox/a.out 00602000-00603000 rw-p 00002000 08:05 132394 /home/barker/sandbox/a.out 01ed8000-01ef9000 rw-p 00000000 00:00 0 [heap] 7fadbebed000-7fadbec02000 r-xp 00000000 08:05 7340318 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fadbec02000-7fadbee01000 ---p 00015000 08:05 7340318 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fadbee01000-7fadbee02000 r--p 00014000 08:05 7340318 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fadbee02000-7fadbee03000 rw-p 00015000 08:05 7340318 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fadbee03000-7fadbeefc000 r-xp 00000000 08:05 7340241 /lib/x86_64-linux-gnu/libm-2.15.so 7fadbeefc000-7fadbf0fb000 ---p 000f9000 08:05 7340241 /lib/x86_64-linux-gnu/libm-2.15.so 7fadbf0fb000-7fadbf0fc000 r--p 000f8000 08:05 7340241 /lib/x86_64-linux-gnu/libm-2.15.so 7fadbf0fc000-7fadbf0fd000 rw-p 000f9000 08:05 7340241 /lib/x86_64-linux-gnu/libm-2.15.so 7fadbf0fd000-7fadbf132000 r-xp 00000000 08:05 393626 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0 7fadbf132000-7fadbf331000 ---p 00035000 08:05 393626 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0 7fadbf331000-7fadbf332000 r--p 00034000 08:05 393626 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0 7fadbf332000-7fadbf333000 rw-p 00035000 08:05 393626 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0 7fadbf333000-7fadbf4e6000 r-xp 00000000 08:05 7340313 /lib/x86_64-linux-gnu/libc-2.15.so 7fadbf4e6000-7fadbf6e5000 ---p 001b3000 08:05 7340313 /lib/x86_64-linux-gnu/libc-2.15.so 7fadbf6e5000-7fadbf6e9000 r--p 001b2000 08:05 7340313 /lib/x86_64-linux-gnu/libc-2.15.so 7fadbf6e9000-7fadbf6eb000 rw-p 001b6000 08:05 7340313 /lib/x86_64-linux-gnu/libc-2.15.so 7fadbf6eb000-7fadbf6f0000 rw-p 00000000 00:00 0 7fadbf6f0000-7fadbf804000 r-xp 00000000 08:05 393401 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0 7fadbf804000-7fadbfa04000 ---p 00114000 08:05 393401 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0 7fadbfa04000-7fadbfa05000 r--p 00114000 08:05 393401 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0 7fadbfa05000-7fadbfa07000 rw-p 00115000 08:05 393401 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0 7fadbfa07000-7fadbfa29000 r-xp 00000000 08:05 7340317 /lib/x86_64-linux-gnu/ld-2.15.so 7fadbfc04000-7fadbfc08000 rw-p 00000000 00:00 0 7fadbfc26000-7fadbfc29000 rw-p 00000000 00:00 0 7fadbfc29000-7fadbfc2a000 r--p 00022000 08:05 7340317 /lib/x86_64-linux-gnu/ld-2.15.so 7fadbfc2a000-7fadbfc2c000 rw-p 00023000 08:05 7340317 /lib/x86_64-linux-gnu/ld-2.15.so 7fff13969000-7fff1398b000 rw-p 00000000 00:00 0 [stack] 7fff139d5000-7fff139d6000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted (core dumped) module class_Foo implicit none type :: SubFoo integer :: num end type type :: Foo class(SubFoo), allocatable :: aSubFoo end type Foo type :: SuperFoo type(Foo), allocatable, dimension(:) :: foos end type end module class_Foo program testdealloc use class_Foo implicit none type(SuperFoo) :: mySuperFoo type(Foo), allocatable, dimension(:) :: myFoos type(SubFoo) :: mySubFoo mySubFoo=SubFoo(1) allocate(myFoos(10)) allocate(myFoos(1)%aSubFoo, source=mySubFoo) mySuperFoo = SuperFoo(myFoos) deallocate(mySuperFoo%foos) end program testdealloc
(In reply to comment #16) > I found that the following nested deallocation program still fails in 4.6.3. I can confirm that it fails with 4.6.3. However, it works for me with 4.7.0 and 4.8 trunk.
> > I found that the following nested deallocation program still fails in 4.6.3.> > > I can confirm that it fails with 4.6.3. However, it works for me with 4.7.0 and 4.8 trunk. I confirm that it works for me with GNU Fortran (Ubuntu/Linaro 4.7.0-7ubuntu3) 4.7.0
Finally closing as fixed.