]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
fortran: [PR125535] wrong-code for implied-do with allocatable-component
authorJerry DeLisle <jvdelisle@gcc.gnu.org>
Fri, 5 Jun 2026 20:20:05 +0000 (13:20 -0700)
committerJerry DeLisle <jvdelisle@gcc.gnu.org>
Sun, 7 Jun 2026 19:34:02 +0000 (12:34 -0700)
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.

gcc/fortran/trans-expr.cc
gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90 [new file with mode: 0644]

index c808c1b3ef32a5253e1c213fbe0a02982d40276e..00925f2ef5af9478369e40bd351ba18e1b3d2688 100644 (file)
@@ -9069,12 +9069,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
   /* Follow the function call with the argument post block.  */
   if (byref)
     {
-      gfc_add_block_to_block (&se->pre, &post);
-
       /* Transformational functions of derived types with allocatable
-        components must have the result allocatable components copied when the
-        argument is actually given.  This is unnecessry for REDUCE because the
-        wrapper for the OPERATION function takes care of this.  */
+        components must have the result allocatable components copied
+        BEFORE the argument post block is appended.  Copying the result
+        first, then freeing the argument, gives the correct order.  */
       arg = expr->value.function.actual;
       if (result && arg && expr->rank
          && isym && isym->transformational
@@ -9102,6 +9100,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                                            NULL, GFC_CAF_COARRAY_NOCOARRAY);
          gfc_add_expr_to_block (&se->pre, tmp);
        }
+
+      gfc_add_block_to_block (&se->pre, &post);
     }
   else
     {
diff --git a/gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90 b/gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90
new file mode 100644 (file)
index 0000000..8f0ae49
--- /dev/null
@@ -0,0 +1,39 @@
+! { dg-do run }
+! Test that a nested implied-do array constructor with a derived-type
+! constructor whose argument uses an outer loop variable produces correct
+! results when the derived type has an allocatable component.
+!
+! PR fortran/125535
+
+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 implied_do_alloc_comp
+  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.]
+
+  ! Nested implied-do where inner DT constructor uses outer variable i.
+  ! Without the fix this produces heap-use-after-free and wrong values.
+  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