Hi all,
The attached patch fixes this per the ChangeLog. While testing the
double call fix I discovered the a memory leak problem. The patch is
fairly straight forward.
Regression tested on x86_64. New test case.
Ok for mainline?
Regards,
Jerry
---
fortran: [PR53296] Fix character array-ctor function called
twice
Avoid the redundant generated call to the pre chain when
no_function_call is set.
Also fix a related stack-buffer-overflow: gfc_conv_array_parameter
wrote over the array constructor's. The specified length was to short.
Use the explicit character type-spec length instead.
PR fortran/53296
gcc/fortran/ChangeLog:
* trans-expr.cc (gfc_conv_procedure_call): Skip the redundant
function call added to the pre chain when no_function_call is
set and the character result length was already determined
without running the callee.
* trans-array.cc (gfc_conv_array_parameter): Convert an array
constructor's explicit character type-spec length directly
instead of using the first elements length.
gcc/testsuite/ChangeLog:
* gfortran.dg/array_constructor_59.f90: New test.
---
From 5d53945cf4fc674eef18c2d8c8075e5b8624be3c Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Tue, 21 Jul 2026 09:15:50 -0700
Subject: [PATCH] fortran: [PR53296] Fix character array-ctor function called
twice
Avoid the redundant generated call to the pre chain when
no_function_call is set.
Also fix a related stack-buffer-overflow: gfc_conv_array_parameter
wrote over the array constructor's. The specified length was to short.
Use the explicit character type-spec length instead.
PR fortran/53296
gcc/fortran/ChangeLog:
* trans-expr.cc (gfc_conv_procedure_call): Skip the redundant
function call added to the pre chain when no_function_call is
set and the character result length was already determined
without running the callee.
* trans-array.cc (gfc_conv_array_parameter): Convert an array
constructor's explicit character type-spec length directly
instead of using the first elements length.
gcc/testsuite/ChangeLog:
* gfortran.dg/array_constructor_59.f90: New test.
---
gcc/fortran/trans-array.cc | 15 +++++++++++-
gcc/fortran/trans-expr.cc | 9 +++++++-
.../gfortran.dg/array_constructor_59.f90 | 23 +++++++++++++++++++
3 files changed, 45 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gfortran.dg/array_constructor_59.f90
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index b60e0c10b6a..cf7eddf6e1d 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -8908,7 +8908,20 @@ gfc_conv_array_parameter (gfc_se *se, gfc_expr *expr, bool g77,
if (expr->expr_type == EXPR_ARRAY && expr->ts.type == BT_CHARACTER)
{
- get_array_ctor_strlen (&se->pre, expr->value.constructor, &tmp);
+ if (expr->ts.u.cl->length_from_typespec && expr->ts.u.cl->length)
+ {
+ /* The constructor has an explicit character type-spec length
+ so convert it directly. */
+ gfc_se cse;
+ gfc_init_se (&cse, NULL);
+ gfc_conv_expr_type (&cse, expr->ts.u.cl->length,
+ gfc_charlen_type_node);
+ gfc_add_block_to_block (&se->pre, &cse.pre);
+ tmp = cse.expr;
+ }
+ else
+ get_array_ctor_strlen (&se->pre, expr->value.constructor, &tmp);
+
expr->ts.u.cl->backend_decl = tmp;
se->string_length = tmp;
}
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index db33bcdd15d..2c24a6717f5 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -7046,6 +7046,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
int arglen;
unsigned int argc;
tree arg1_cntnr = NULL_TREE;
+ bool call_needed_for_length = true;
arglist = NULL;
retargs = NULL;
stringargs = NULL;
@@ -8767,6 +8768,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
fold_convert (gfc_charlen_type_node, tmp),
build_zero_cst (gfc_charlen_type_node));
cl.backend_decl = tmp;
+
+ /* The length was fully computed above from the specification
+ expression, without needing the callee to actually run. */
+ call_needed_for_length = false;
}
/* Set up a charlen structure for it. */
@@ -9076,7 +9081,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
if (byref)
{
/* Add the function call to the pre chain. There is no expression. */
- gfc_add_expr_to_block (&se->pre, se->expr);
+ if (!se->no_function_call || call_needed_for_length)
+ gfc_add_expr_to_block (&se->pre, se->expr);
+
se->expr = NULL_TREE;
if (!se->direct_byref)
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_59.f90 b/gcc/testsuite/gfortran.dg/array_constructor_59.f90
new file mode 100644
index 00000000000..31169163a3e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/array_constructor_59.f90
@@ -0,0 +1,23 @@
+! { dg-do run }
+! PR fortran/53296
+! Test case based on the test case from Steve Kargl
+program pr53296
+ implicit none
+ character(len=128) :: str(2)
+ integer :: ncalls = 0
+
+ str = [ucase("abcde"), ucase("ghij")]
+ if (ncalls /= 2) stop 1
+ if (trim (str(1)) /= "abcde") stop 2
+ if (trim (str(2)) /= "ghij") stop 3
+
+contains
+
+ function ucase(s)
+ character(*), intent(in) :: s
+ character(len(s)) :: ucase
+ ncalls = ncalls + 1
+ ucase = s
+ end function ucase
+
+end program pr53296
--
2.55.0