When a nested implied-do array constructor calls a transformational intrinsic (e.g. RESHAPE) and the element type is a derived type with allocatable components, gfortran produces wrong runtime values or crashes with a heap-use-after-free. The argument temporaries are freed before the result's allocatable components are deep-copied. Since RESHAPE does a shallow byte-copy, the result's component pointers alias those of the temporaries, so freeing first yields use-after-free. module m implicit none type :: t real, allocatable :: v(:) end type contains pure function make (x) result (r) real, intent(in) :: x(:) type(t) :: r r%v = x end function end module program test use m implicit none integer, parameter :: n = 3, k = 2 type(t), allocatable :: a(:,:) real :: h(k, n) integer :: i, j h(1,:) = [10., 20., 30.] h(2,:) = [11., 21., 31.] a = reshape ([([(make (h(:,i)), j=1,1)], i=1,n)], [1,n]) if (any (a(1,1)%v /= h(:,1))) stop 1 if (any (a(1,2)%v /= h(:,2))) stop 2 if (any (a(1,3)%v /= h(:,3))) stop 3 end program $ gfortran implied_do_alloc_comp_1.f90 && ./a.out The program stops at STOP 1 or crashes with a heap-use-after-free. It should run and exit cleanly. This one could be related to 90519 and 96910, not sure
The master branch has been updated by Jerry DeLisle <jvdelisle@gcc.gnu.org>: https://gcc.gnu.org/g:b5a3b874b8df2ea2ca82bd97fcd5906f7ebe82d8 commit r17-1410-gb5a3b874b8df2ea2ca82bd97fcd5906f7ebe82d8 Author: Jerry DeLisle <jvdelisle@gcc.gnu.org> Date: Fri Jun 5 13:20:05 2026 -0700 fortran: [PR125535] wrong-code for implied-do with allocatable-component When a nested implied-do array constructor called a transformational intrinsic (e.g. RESHAPE) whose result type has allocatable components, the argument temporaries were freed before the result's allocatable components were deep-copied, causing a heap-use-after-free and wrong runtime values. Transformational library functions such as RESHAPE do a shallow byte-copy of the source array into the result, so the result's component pointers alias those of the argument temporaries. Freeing the temporaries first and then copying yielded use-after-free. Move gfc_add_block_to_block (&se->pre, &post) to after the deep-copy loop, so that the result's allocatable components are copied while the source storage is still live. Assisted by: Claude Sonnet 4.6 PR fortran/125535 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Move post block append to after the deep copy of allocatable components for transformational intrinsics, so that argument temporaries are not freed before the result components are copied. gcc/testsuite/ChangeLog: * gfortran.dg/implied_do_alloc_comp_1.f90: New test.
Followup patch submitted for approval to fix a discovered memory leak, https://gcc.gnu.org/pipermail/fortran/2026-June/064102.html
The releases/gcc-16 branch has been updated by Jerry DeLisle <jvdelisle@gcc.gnu.org>: https://gcc.gnu.org/g:d1750d8df75f292a0111e94dda82664c988bcc60 commit r16-9101-gd1750d8df75f292a0111e94dda82664c988bcc60 Author: Jerry DeLisle <jvdelisle@gcc.gnu.org> Date: Fri Jun 5 13:20:05 2026 -0700 fortran: wrong-code for implied-do with allocatable-component derived type When a nested implied-do array constructor called a transformational intrinsic (e.g. RESHAPE) whose result type has allocatable components, the argument temporaries were freed before the result's allocatable components were deep-copied, causing a heap-use-after-free and wrong runtime values. The root cause: in gfc_conv_procedure_call, the call to gfc_add_block_to_block (&se->pre, &post) â which frees the allocatable components of argument temporaries â was issued before the deep-copy loop for the result's allocatable components. Transformational library functions such as RESHAPE do a shallow byte-copy of the source array into the result, so the result's component pointers alias those of the argument temporaries. Freeing the temporaries first and then copying yielded use-after-free. Fix: move gfc_add_block_to_block (&se->pre, &post) to after the deep-copy loop, so that the result's allocatable components are copied while the source storage is still live. PR fortran/125535 Assisted-by: Claude Sonnet 4.6 gcc/fortran/ChangeLog: PR fortran/125535 * trans-expr.cc (gfc_conv_procedure_call): Move post block append to after the deep copy of allocatable components for transformational intrinsics, so that argument temporaries are not freed before the result components are copied. gcc/testsuite/ChangeLog: PR fortran/125535 * gfortran.dg/implied_do_alloc_comp_1.f90: New test. (cherry picked from commit a0d7e1c3639a6e19f4413bf53bb1e994494ec77f)
The releases/gcc-16 branch has been updated by Jerry DeLisle <jvdelisle@gcc.gnu.org>: https://gcc.gnu.org/g:1da2423372115bf33c9885ccd681ca800d848e49 commit r16-9111-g1da2423372115bf33c9885ccd681ca800d848e49 Author: Jerry DeLisle <jvdelisle@gcc.gnu.org> Date: Thu Jun 11 18:50:37 2026 -0700 fortran: [PR125535] Plug remaining leak in implied-do array constructor with allocatable components Follow-up to the PR fortran/125535 wrong-code fix (commit 1b8421e9d5b, already pushed): that fix corrected the *values* produced by an implied-do array constructor of derived-type function results with allocatable components, but left a separate memory leak in the same code path. An array constructor whose implied-do produces function results of a derived type with allocatable components moves each result into the constructor temporary, so the temporary owns those components. The per-element finalization in gfc_trans_array_ctor_element only freed the single slot referenced by the final loop offset, leaking the allocatable components of every other element the loop produced. A whole-array sweep is the only way to free every slot written by an implied-do, but it may be used only when every element is an owned function result: a variable element is shallow-copied into the temporary and its components are aliased rather than owned, so freeing them would double free. Add gfc_constructor_is_owned_alloc_comp to detect the all-owned case and, when it holds, suppress the per-element finalization and emit a single gfc_deallocate_alloc_comp_no_caf over the whole temporary. Assisted-by: Claude Opus 4.8 PR fortran/125535 gcc/fortran/ChangeLog: * trans-array.cc (gfc_constructor_is_owned_alloc_comp): New function. (gfc_trans_array_constructor_value): Add OWNED_SWEEP parameter and, when set, suppress the per-element finalization. Pass it through the recursive call. (trans_array_constructor): Compute OWNED_SWEEP and, when set, deallocate the allocatable components of the whole temporary in one sweep. gcc/testsuite/ChangeLog: * gfortran.dg/asan/implied_do_alloc_comp_leak_1.f90: New test. (cherry picked from commit b2ec4ebcf914f32f51c35dbd9a2c98dab5841097)
The master branch has been updated by Jerry DeLisle <jvdelisle@gcc.gnu.org>: https://gcc.gnu.org/g:ccfe2771c6f5272a74561ed5ce02f8569f248607 commit r17-1667-gccfe2771c6f5272a74561ed5ce02f8569f248607 Author: Jerry DeLisle <jvdelisle@gcc.gnu.org> Date: Thu Jun 11 18:50:37 2026 -0700 fortran: [PR125535] Plug remaining leak in implied-do array constructor with allocatable components Follow-up to the PR fortran/125535 wrong-code fix (commit 1b8421e9d5b, already pushed): that fix corrected the *values* produced by an implied-do array constructor of derived-type function results with allocatable components, but left a separate memory leak in the same code path. An array constructor whose implied-do produces function results of a derived type with allocatable components moves each result into the constructor temporary, so the temporary owns those components. The per-element finalization in gfc_trans_array_ctor_element only freed the single slot referenced by the final loop offset, leaking the allocatable components of every other element the loop produced. A whole-array sweep is the only way to free every slot written by an implied-do, but it may be used only when every element is an owned function result: a variable element is shallow-copied into the temporary and its components are aliased rather than owned, so freeing them would double free. Add gfc_constructor_is_owned_alloc_comp to detect the all-owned case and, when it holds, suppress the per-element finalization and emit a single gfc_deallocate_alloc_comp_no_caf over the whole temporary. PR fortran/125535 gcc/fortran/ChangeLog: * trans-array.cc (gfc_constructor_is_owned_alloc_comp): New function. (gfc_trans_array_constructor_value): Add OWNED_SWEEP parameter and, when set, suppress the per-element finalization. Pass it through the recursive call. (trans_array_constructor): Compute OWNED_SWEEP and, when set, deallocate the allocatable components of the whole temporary in one sweep. gcc/testsuite/ChangeLog: * gfortran.dg/asan/implied_do_alloc_comp_leak_1.f90: New test.
Fixed and closing