https://gcc.gnu.org/g:7e7412042e90ec1b6f1268049061bcdc208ae267
commit r15-11226-g7e7412042e90ec1b6f1268049061bcdc208ae267 Author: Jakub Jelinek <[email protected]> Date: Fri May 1 14:54:35 2026 +0200 strlen: Adjust objsz arg in __strcat_chk -> __stpcpy_chk transformation [PR125079] As the following testcase shows, we have two different transformations of __strcat_chk. One done in strlen_pass::handle_builtin_strcat, which transforms __strcat_chk (x, y, z) if we know beforehand strlen (x), so something like: l = strlen (x); __strcat_chk (x, y, z); and since PR87672 we change that to l = strlen (x); __strcpy_chk (x + l, y, z - l); i.e. decrease the objsz in if (objsz) { objsz = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (objsz), objsz, fold_convert_loc (loc, TREE_TYPE (objsz), unshare_expr (dstlen))); objsz = force_gimple_operand_gsi (&m_gsi, objsz, true, NULL_TREE, true, GSI_SAME_STMT); } And another transformation is when we have earlier __strcat_chk (x, y, z) call and want to compute strlen (x) after that. In that case get_string_length transforms __strcat_chk (x, y, z); to t = strlen (x); l = __stpcpy_chk (x + t, y, z) - x; where l is the len we are looking for. This patch changes it similarly to the PR87672 to t = strlen (x); l = __stpcpy_chk (x + t, y, z - t) - x; instead. 2026-05-01 Jakub Jelinek <[email protected]> PR tree-optimization/125079 * tree-ssa-strlen.cc (get_string_length): Transform __strcat_chk (x, y, z) when we need strlen (x) afterwards into l1 = strlen (x); l = __stpcpy_chk (x + l1, y, z - l1) - x; where l is the strlen (x), instead of using z as last __stpcpy_chk argument. * gcc.dg/strlenopt-97.c: New test. Reviewed-by: Richard Biener <[email protected]> (cherry picked from commit c1aa090bb8e1c23e733bc7beafceb7c34dc713f8) Diff: --- gcc/testsuite/gcc.dg/strlenopt-97.c | 33 +++++++++++++++++++++++++++++++++ gcc/tree-ssa-strlen.cc | 19 +++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/gcc/testsuite/gcc.dg/strlenopt-97.c b/gcc/testsuite/gcc.dg/strlenopt-97.c new file mode 100644 index 000000000000..c4fadbd89425 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-97.c @@ -0,0 +1,33 @@ +/* PR tree-optimization/125079 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-strlen1" } */ +/* { dg-final { scan-tree-dump-times "__builtin___strcpy_chk \\\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-not "__builtin___strcpy_chk \\\(\[^\n\r]*, 64\\\)" "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__builtin___stpcpy_chk \\\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-not "__builtin___stpcpy_chk \\\(\[^\n\r]*, 128\\\)" "strlen1" } } */ + +typedef __SIZE_TYPE__ size_t; +void foo (char *, int); +char *stpcpy (char *, const char *); + +size_t +bar (char *r) +{ + char buf[64]; + foo (buf, 0); + size_t ret = __builtin_strlen (buf); + __builtin___strcat_chk (buf, r, 64); + foo (buf, 1); + return ret; +} + +size_t +baz (char *r) +{ + char buf[128]; + foo (buf, 2); + __builtin___strcat_chk (buf, r, 128); + size_t ret = __builtin_strlen (buf); + foo (buf, 3); + return ret; +} diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc index c5e9c0b94c62..8057da7bbd4e 100644 --- a/gcc/tree-ssa-strlen.cc +++ b/gcc/tree-ssa-strlen.cc @@ -848,7 +848,7 @@ get_string_length (strinfo *si) attempt to compute the length from the call statement. */ if (si->stmt) { - gimple *stmt = si->stmt, *lenstmt; + gimple *stmt = si->stmt, *lenstmt = NULL, *g; tree callee, lhs, fn, tem; location_t loc; gimple_stmt_iterator gsi; @@ -883,11 +883,11 @@ get_string_length (strinfo *si) lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE, true, GSI_SAME_STMT); } - lenstmt = gimple_build_assign + g = gimple_build_assign (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))), POINTER_PLUS_EXPR,tem, lhs); - gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT); - gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt)); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + gimple_call_set_arg (stmt, 0, gimple_assign_lhs (g)); lhs = NULL_TREE; /* FALLTHRU */ case BUILT_IN_STRCPY: @@ -906,6 +906,17 @@ get_string_length (strinfo *si) gimple_call_set_fndecl (stmt, fn); lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt); gimple_call_set_lhs (stmt, lhs); + if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRCAT_CHK) + { + tree objsz = gimple_call_lhs (lenstmt); + gimple *g + = gimple_build_assign (make_ssa_name (TREE_TYPE (objsz)), + MINUS_EXPR, gimple_call_arg (stmt, 2), + objsz); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + gimple_call_set_arg (stmt, 2, gimple_assign_lhs (g)); + } update_stmt (stmt); if (dump_file && (dump_flags & TDF_DETAILS) != 0) {
