https://gcc.gnu.org/g:dff66a690f6d47963e5cb96677d0e194b85948fa

commit r16-1696-gdff66a690f6d47963e5cb96677d0e194b85948fa
Author: Andre Vehreschild <ve...@gcc.gnu.org>
Date:   Wed Jun 25 09:12:35 2025 +0200

    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.

Diff:
---
 gcc/fortran/trans-array.cc                         | 10 ++++++----
 .../gfortran.dg/asan/array_constructor_1.f90       | 23 ++++++++++++++++++++++
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 3d274439895d..7be2d7b11a62 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 000000000000..45eafacd5a67
--- /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

Reply via email to