[PATCH] PR125535 wrong-code for implied-do with allocatable-component, derived type and transformational intrinsic

Jerry D <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.fortran
Message-ID <[email protected]>
See attached patch.

This one is fairly simple. This is also the last of the meta-bug PR125515.

Regression tested on x86_64.

I will probably simplify the commit message. Thought I should comments before I 
do that.

OK for mainline and later backport to 16.

Regards,

Jerry

---


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.
---
PR125535-implied-do-alloc-comp.patch (text/x-patch, 4.5 KB)
From 7b0e7473fc53127f70276cdd3e33268e3b867c7b Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Fri, 5 Jun 2026 13:20:05 -0700
Subject: [PATCH] fortran: wrong-code for implied-do with allocatable-component
 derived type and transformational intrinsic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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.
---
 gcc/fortran/trans-expr.cc                     | 10 ++---
 .../gfortran.dg/implied_do_alloc_comp_1.f90   | 39 +++++++++++++++++++
 2 files changed, 44 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index c808c1b3ef3..00925f2ef5a 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -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
index 00000000000..8f0ae4976d8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90
@@ -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
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.