]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
strlen: Adjust objsz arg in __strcat_chk -> __stpcpy_chk transformation [PR125079]
authorJakub Jelinek <jakub@redhat.com>
Fri, 1 May 2026 12:54:35 +0000 (14:54 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 1 May 2026 12:54:35 +0000 (14:54 +0200)
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  <jakub@redhat.com>

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 <rguenth@suse.de>
gcc/testsuite/gcc.dg/strlenopt-97.c [new file with mode: 0644]
gcc/tree-ssa-strlen.cc

diff --git a/gcc/testsuite/gcc.dg/strlenopt-97.c b/gcc/testsuite/gcc.dg/strlenopt-97.c
new file mode 100644 (file)
index 0000000..c4fadbd
--- /dev/null
@@ -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;
+}
index ed4df00c72b86fe3733291a620715d7a2c8990fb..d6949441f3164b228fba838fe252994c922cce0c 100644 (file)
@@ -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;
       tree callee, lhs, fn, tem;
       location_t loc;
       gimple_stmt_iterator gsi;
@@ -902,6 +902,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)
            {