Hello Jerry,

Contrary to my remark on Mattermost, this looks good to me except that
I would halve the size of the patch by refactoring it as in the
attached version. It passes regression testing like the original.

OK for mainline and backporting later on.

Thanks for re-examining this Golden Oldie!

Paul

On Wed, 3 Jun 2026 at 02:32, Jerry D <[email protected]> wrote:
>
> Hi all,
>
> I tried something a little different. This patch regression tested on x86_64.
> The original bug report dates from 2019.
>
> The patch fixes the issue found with -fsanitizer=address.
>
> OK for mainline? Looks like it ought to be backported after a brief wait.
>
> Regards,
>
> Jerry
> ---
> When an assumed-rank type(T) dummy argument was passed to an assumed-rank
> class(T) dummy argument, gfortran generated a GFC_MAX_DIMENSIONS static
> struct copy of the array descriptor's dim[] array.  The caller only
> allocates storage for dtype.rank dimensions, so the copy read past the
> physical end of the descriptor causing a stack-buffer-overflow detected
> by AddressSanitizer.
>
> Fix by checking expr->rank == -1 (assumed-rank actual) at the two copy
> sites and replacing the static copy with a runtime-sized __builtin_memcpy
> of dtype.rank * sizeof(descriptor_dimension) bytes.
>
> Assisted-By: Claude Sonnet 4.6
>
>         PR fortran/60576
>
> gcc/fortran/ChangeLog:
>
>         PR fortran/60576
>         * trans-array.cc (gfc_conv_array_parameter): For an assumed-rank
>         actual argument passed to a CLASS assumed-rank formal, use a
>         runtime-sized memcpy for the dim[] entries instead of a full
>         GFC_MAX_DIMENSIONS static copy.
>         * trans-expr.cc (gfc_conv_derived_to_class): Likewise for the
>         derived_array descriptor copy.
>
> gcc/testsuite/ChangeLog:
>
>         PR fortran/60576
>         * gfortran.dg/assumed_rank_26.f90: New test.
> ---
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 3e3f4f00b25..efa08fa8d58 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9231,6 +9231,37 @@ is_pointer (gfc_expr *e)
   return sym->attr.pointer || sym->attr.proc_pointer;
 }
 
+
+/* Assumed-rank actual argument: the caller only allocates storage for dtype
+   rank dimensions. Copying GFC_MAX_DIMENSIONS dim entries would read past the
+   physical end of the descriptor. Copy the header fields explicitly and use a
+   runtime-sized memcpy for the dim[] entries.  */
+
+void
+gfc_resize_assumed_rank_dim_field (gfc_se *se, stmtblock_t *block, tree desc)
+{
+  tree rank, dim_field, dim_size, copy_size, dst_ptr, src_ptr;
+
+  gfc_conv_descriptor_data_set (block, desc,
+				gfc_conv_descriptor_data_get (se->expr));
+  gfc_conv_descriptor_offset_set (block, desc,
+				  gfc_conv_descriptor_offset_get (se->expr));
+  gfc_add_modify (block, gfc_conv_descriptor_dtype (desc),
+		  gfc_conv_descriptor_dtype (se->expr));
+  rank = fold_convert (size_type_node, gfc_conv_descriptor_rank (se->expr));
+  dim_field = gfc_get_descriptor_dimension (se->expr);
+  dim_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (dim_field)));
+  copy_size = fold_build2_loc (input_location, MULT_EXPR,
+			       size_type_node, rank, dim_size);
+  dst_ptr = gfc_build_addr_expr (pvoid_type_node,
+				 gfc_get_descriptor_dimension (desc));
+  src_ptr = gfc_build_addr_expr (pvoid_type_node, dim_field);
+  gfc_add_expr_to_block (block, build_call_expr_loc (input_location,
+			 builtin_decl_explicit (BUILT_IN_MEMCPY),
+			 3, dst_ptr, src_ptr, copy_size));
+}
+
+
 /* Convert an array for passing as an actual parameter.  */
 
 void
@@ -9505,7 +9536,10 @@ gfc_conv_array_parameter (gfc_se *se, gfc_expr *expr, bool g77,
 	      gfc_conv_descriptor_offset_set (&block, arr, gfc_index_zero_node);
 	      se->expr = arr;
 	    }
-	  gfc_class_array_data_assign (&block, tmp, se->expr, true);
+	  if (expr->rank == -1)
+	    gfc_resize_assumed_rank_dim_field (se, &block, tmp);
+	  else
+	    gfc_class_array_data_assign (&block, tmp, se->expr, true);
 
 	  /* Handle optional.  */
 	  if (fsym && fsym->attr.optional && sym && sym->attr.optional)
diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h
index 4b51e546904..66d027dc44c 100644
--- a/gcc/fortran/trans-array.h
+++ b/gcc/fortran/trans-array.h
@@ -152,6 +152,8 @@ void gfc_get_dataptr_offset (stmtblock_t*, tree, tree, tree, bool, gfc_expr*);
 tree gfc_get_array_span (tree, gfc_expr *);
 /* Evaluate an array expression.  */
 void gfc_conv_expr_descriptor (gfc_se *, gfc_expr *);
+/* Resize the dim fields of an assumed size descriptor.  */
+void gfc_resize_assumed_rank_dim_field (gfc_se *, stmtblock_t *, tree);
 /* Convert an array for passing as an actual function parameter.  */
 void gfc_conv_array_parameter (gfc_se *, gfc_expr *, bool, const gfc_symbol *,
 			       const char *, tree *, tree * = nullptr,
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index e64ffc12b71..0e90d078b90 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -1028,7 +1028,10 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e, gfc_symbol *fsym,
 	    {
 	      *derived_array
 		= gfc_create_var (TREE_TYPE (parmse->expr), "array");
-	      gfc_add_modify (&block, *derived_array, parmse->expr);
+	      if (e->rank == -1)
+		gfc_resize_assumed_rank_dim_field (parmse, &block, *derived_array);
+	      else
+		gfc_add_modify (&block, *derived_array, parmse->expr);
 	    }
 
 	  if (optional)

Reply via email to