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)
+ {
+ /* 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. PR fortran/60576. */
+ tree rank, dim_field, dim_size, copy_size, dst_ptr, src_ptr;
+
+ gfc_conv_descriptor_data_set (&block, tmp,
+ gfc_conv_descriptor_data_get (se->expr));
+ gfc_conv_descriptor_offset_set (&block, tmp,
+ gfc_conv_descriptor_offset_get (se->expr));
+ gfc_add_modify (&block, gfc_conv_descriptor_dtype (tmp),
+ 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 (tmp));
+ 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));
+ }
+ else if (CLASS_DATA (fsym)->as->rank == -1)
+ /* Fixed-rank actual to class assumed-rank formal: the formal's
+ class descriptor has dim_t[GFC_MAX_DIMENSIONS]; use lhs_type=false
+ so the ARRAY_RANGE_REF is sized by TREE_TYPE(rhs_dim) = dim_t[rank],
+ copying only the physically present entries. PR fortran/60576. */
+ gfc_class_array_data_assign (&block, tmp, se->expr, false);
+ else
+ gfc_class_array_data_assign (&block, tmp, se->expr, true);
/* Handle optional. */
if (fsym && fsym->attr.optional && sym && sym->attr.optional)
{
*derived_array
= gfc_create_var (TREE_TYPE (parmse->expr), "array");
- gfc_add_modify (&block, *derived_array, parmse->expr);
+ if (e->rank == -1)
+ {
+ /* Assumed-rank actual: parmse->expr physically holds only
+ dtype.rank dims; a full struct assign reads past the end.
+ Copy field-by-field with a runtime-sized dim[] memcpy.
+ PR fortran/60576. */
+ tree rank, dim_field, dim_size, copy_size, dst_ptr, src_ptr;
+
+ gfc_conv_descriptor_data_set
+ (&block, *derived_array,
+ gfc_conv_descriptor_data_get (parmse->expr));
+ gfc_conv_descriptor_offset_set
+ (&block, *derived_array,
+ gfc_conv_descriptor_offset_get (parmse->expr));
+ gfc_add_modify (&block,
+ gfc_conv_descriptor_dtype (*derived_array),
+ gfc_conv_descriptor_dtype (parmse->expr));
+ rank = fold_convert (size_type_node,
+ gfc_conv_descriptor_rank (parmse->expr));
+ dim_field = gfc_get_descriptor_dimension (parmse->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 (*derived_array));
+ 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));
+ }
+ else
+ gfc_add_modify (&block, *derived_array, parmse->expr);
}
if (optional)
--- /dev/null
+! { dg-do run }
+!
+! PR fortran/60576
+!
+! Stack buffer overflow when passing an assumed-rank type(T) dummy argument
+! to an assumed-rank class(T) dummy argument. The caller only allocates
+! storage for dtype.rank dimensions in the descriptor; generating a full
+! GFC_MAX_DIMENSIONS copy caused a stack-buffer-overflow detected by ASan.
+
+implicit none
+type t
+ integer :: i
+end type
+
+type(T) :: at(2:3,2:4)
+integer :: i = 0
+
+call bar(at)
+if (i /= 2) STOP 1
+
+contains
+ subroutine bar(x)
+ type(t) :: x(..)
+ if (lbound(x,1) /= 1 .or. lbound(x,2) /= 1) STOP 2
+ if (size(x) /= 6) STOP 3
+ if (size(x,1) /= 2 .or. size(x,2) /= 3) STOP 4
+ if (ubound(x,1) /= 2 .or. ubound(x,2) /= 3) STOP 5
+ i = i + 1
+ call foo(x)
+ end subroutine
+ subroutine foo(x)
+ class(t) :: x(..)
+ if (lbound(x,1) /= 1 .or. lbound(x,2) /= 1) STOP 6
+ if (size(x) /= 6) STOP 7
+ if (size(x,1) /= 2 .or. size(x,2) /= 3) STOP 8
+ if (ubound(x,1) /= 2 .or. ubound(x,2) /= 3) STOP 9
+ i = i + 1
+ end subroutine
+end