Hi all,

attached patch fixes an out of bounds access in the clean up code of a
concatenating array constructor. A fragment like

list = [ list, something() ]

lead to clean up using an offset (of the list array) that was manipulated in
the loop copying the existing array elements and at the end pointing to one
element past the list (after the concatenation). 

This fixes a 15-regression. Releases prior to 15 do not have the out
of bounds access in the (non existing) clean up code. The have a memory
leak instead.

Regtested ok on x86_64-pc-linux-gnu / F41. Ok for mainline?

The subject says, that there will be 3 patches. Only this one fixes the bug.
The other fixes I found while hunting this issue and because they play in the
general same area, I don't want to loose them. I therefore publish them in this
context. 

Regards,
        Andre
-- 
Andre Vehreschild * Email: vehre ad gmx dot de 
From 548bcaeff9b8c8d6bb670574883f7b02878e3221 Mon Sep 17 00:00:00 2001
From: Andre Vehreschild <ve...@gcc.gnu.org>
Date: Wed, 25 Jun 2025 09:12:35 +0200
Subject: [PATCH 1/3] Fortran: Fix out of bounds access in structure
 constructor's clean up [PR120711]

A structure constructor's generated clean up code was using an offset
variable, which was manipulated before the clean up was run leading to
an out of bounds access.

	PR fortran/120711

gcc/fortran/ChangeLog:

	* trans-array.cc (gfc_trans_array_ctor_element): Store the value
	of the offset for reuse.

gcc/testsuite/ChangeLog:

	* gfortran.dg/asan/array_constructor_1.f90: New test.
---
 gcc/fortran/trans-array.cc                    | 10 ++++----
 .../gfortran.dg/asan/array_constructor_1.f90  | 23 +++++++++++++++++++
 2 files changed, 29 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 3d274439895..7be2d7b11a6 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -1991,14 +1991,17 @@ static void
 gfc_trans_array_ctor_element (stmtblock_t * pblock, tree desc,
 			      tree offset, gfc_se * se, gfc_expr * expr)
 {
-  tree tmp;
+  tree tmp, offset_eval;
 
   gfc_conv_expr (se, expr);
 
   /* Store the value.  */
   tmp = build_fold_indirect_ref_loc (input_location,
 				 gfc_conv_descriptor_data_get (desc));
-  tmp = gfc_build_array_ref (tmp, offset, NULL);
+  /* The offset may change, so get its value now and use that to free memory.
+   */
+  offset_eval = gfc_evaluate_now (offset, &se->pre);
+  tmp = gfc_build_array_ref (tmp, offset_eval, NULL);
 
   if (expr->expr_type == EXPR_FUNCTION && expr->ts.type == BT_DERIVED
       && expr->ts.u.derived->attr.alloc_comp)
@@ -3150,8 +3153,7 @@ finish:
      the reference.  */
   if ((expr->ts.type == BT_DERIVED || expr->ts.type == BT_CLASS)
        && finalblock.head != NULL_TREE)
-    gfc_add_block_to_block (&loop->post, &finalblock);
-
+    gfc_prepend_expr_to_block (&loop->post, finalblock.head);
 }
 
 
diff --git a/gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90 b/gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90
new file mode 100644
index 00000000000..45eafacd5a6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90
@@ -0,0 +1,23 @@
+!{ dg-do run }
+
+! Contributed by Christopher Albert  <alb...@tugraz.at>
+
+program grow_type_array
+    type :: container
+        integer, allocatable :: arr(:)
+    end type container
+    
+    type(container), allocatable :: list(:)
+
+    list = [list, new_elem(5)]
+
+    deallocate(list)
+
+contains
+
+    type(container) function new_elem(s) result(out)
+        integer :: s
+        allocate(out%arr(s))
+    end function new_elem
+      
+end program grow_type_array
-- 
2.49.0

Reply via email to