See the attached patch.

This is a followup to the PR128357 patch fixing the additional case identified by Harald. It turns out to be not too difficult.

Regression tested on x86_64.

OK for mainline?

Regards,

Jerry

---

fortran: [PR128509] Double free with a parenthesized array constructor

The allocatable components of the elements of a parenthesized array
constructor were freed after the call while still shared with the
variables in the constructor, which then freed them again.  The
temporary for the parenthesized expression was a shallow copy of the
constructor's temporary, because only a variable or a constructor got a
deep copy, and for an elemental procedure the parentheses hid the
variables from expr_may_alias_variables.  Treat a parenthesized array
constructor like the constructor in both places.

Assisted-by: Claude Opus 5.5

        PR fortran/128509

gcc/fortran/ChangeLog:

        * trans-array.cc (gfc_conv_expr_descriptor): Copy the temporary for
        a parenthesized array constructor deeply, as for the constructor.
        * trans-expr.cc (expr_may_alias_variables): Look through the
        parentheses around an array constructor.

gcc/testsuite/ChangeLog:

        * gfortran.dg/asan/paren_array_ctor_alloc_comp_1.f90: New test.
---
From b1f4b3f5f6e53dc82e64fc5f1653899ba3b05a10 Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Fri, 6 Nov 2026 10:39:39 -0800
Subject: [PATCH] fortran: [PR128509] Double free with a parenthesized array
 constructor

The allocatable components of the elements of a parenthesized array
constructor were freed after the call while still shared with the
variables in the constructor, which then freed them again.  The
temporary for the parenthesized expression was a shallow copy of the
constructor's temporary, because only a variable or a constructor got a
deep copy, and for an elemental procedure the parentheses hid the
variables from expr_may_alias_variables.  Treat a parenthesized array
constructor like the constructor in both places.

Assisted-by: Claude Opus 5.5

	PR fortran/128509

gcc/fortran/ChangeLog:

	* trans-array.cc (gfc_conv_expr_descriptor): Copy the temporary for
	a parenthesized array constructor deeply, as for the constructor.
	* trans-expr.cc (expr_may_alias_variables): Look through the
	parentheses around an array constructor.

gcc/testsuite/ChangeLog:

	* gfortran.dg/asan/paren_array_ctor_alloc_comp_1.f90: New test.
---
 gcc/fortran/trans-array.cc                    | 10 ++++--
 gcc/fortran/trans-expr.cc                     |  5 +++
 .../asan/paren_array_ctor_alloc_comp_1.f90    | 36 +++++++++++++++++++
 3 files changed, 49 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/asan/paren_array_ctor_alloc_comp_1.f90

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 2a95784d860..48e8634b246 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -8514,9 +8514,15 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
 
       lse.string_length = rse.string_length;
 
+      /* A parenthesized constructor is copied like the constructor.  */
+      gfc_expr *src = expr;
+      if (src->expr_type == EXPR_OP
+	  && src->value.op.op == INTRINSIC_PARENTHESES
+	  && src->value.op.op1->expr_type == EXPR_ARRAY)
+	src = src->value.op.op1;
       deep_copy = !se->data_not_needed
-		  && (expr->expr_type == EXPR_VARIABLE
-		      || expr->expr_type == EXPR_ARRAY);
+		  && (src->expr_type == EXPR_VARIABLE
+		      || src->expr_type == EXPR_ARRAY);
       tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts,
 				     deep_copy, false);
       gfc_add_expr_to_block (&block, tmp);
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 89d9a64de59..4ce442aca1d 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6043,6 +6043,11 @@ expr_may_alias_variables (gfc_expr *e, bool array_may_alias)
 {
   gfc_constructor *c;
 
+  if (e->expr_type == EXPR_OP
+      && e->value.op.op == INTRINSIC_PARENTHESES
+      && e->value.op.op1->expr_type == EXPR_ARRAY)
+    e = e->value.op.op1;
+
   if (e->expr_type == EXPR_VARIABLE)
     return true;
   else if (e->expr_type == EXPR_FUNCTION)
diff --git a/gcc/testsuite/gfortran.dg/asan/paren_array_ctor_alloc_comp_1.f90 b/gcc/testsuite/gfortran.dg/asan/paren_array_ctor_alloc_comp_1.f90
new file mode 100644
index 00000000000..0aa8462ff11
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/asan/paren_array_ctor_alloc_comp_1.f90
@@ -0,0 +1,36 @@
+! { dg-do run }
+!
+! PR 128509
+! The components of a parenthesized array constructor of a type with
+! allocatable components were freed after the call while still shared
+! with TA, which then freed them again.  Checked under -fsanitize=address.
+
+module m
+  implicit none
+  type :: t
+    integer, allocatable :: v(:)
+  end type
+contains
+  subroutine s (x)
+    type(t), intent(in) :: x(:)
+    if (x(2)%v(2) /= 2) stop 1
+  end subroutine
+  elemental subroutine se (x)
+    type(t), intent(in) :: x
+  end subroutine
+  subroutine work ()
+    type(t) :: ta(2)
+
+    ta(1) = t ([1])
+    ta(2) = t ([2, 2])
+    call s (([ta]))
+    call se (([ta]))
+    if (any (ta(2)%v /= 2)) stop 2
+  end subroutine
+end module
+
+program p
+  use m
+  implicit none
+  call work ()
+end program
-- 
2.56.0

Reply via email to