While checking objects whose addresses are passed to functions
declared to take const pointers and making sure they're initialized
the GCC 11 -Wmaybe-uninitialized enhancement assumes that the actual
argument is a pointer.

That's normally a safe assumption because for nonpointer arguments
the front ends add an explicit cast to the expected pointer type.
This doesn't happen for arguments passed through the ellipsis in
calls to variadic functions but those arguments aren't checked by
the enhancement (yet).

But when an invalid call to a variadic function like sprintf is
folded into one to strcpy() such as in the test case below this
assumption breaks and causes an ICE in the uninit pass.

  void f (char *d, int i)
  {
    __builtin_sprintf (d, "%s", i);   // uninit sees strcpy (d, i)
  }

The attached patch solves this by a) avoiding the unsafe assumption
in the uninit pass, and b) avoiding folding sprintf calls with invalid
arguments of nonpointer types to strcpy.

Tested on x86_64-linux.

Martin
PR middle-end/100732 - ICE on sprintf %s with integer argument

gcc/ChangeLog:

	PR middle-end/100732
	* gimple-fold.c (gimple_fold_builtin_sprintf): Avoid folding calls
	with either source or destination argument of invalid type.
	* tree-ssa-uninit.c (maybe_warn_pass_by_reference): Avoid checking
	calls with arguments of invalid type.

gcc/testsuite/ChangeLog:

	PR middle-end/100732
	* gcc.dg/tree-ssa/builtin-snprintf-11.c: New test.
	* gcc.dg/tree-ssa/builtin-snprintf-12.c: New test.
	* gcc.dg/tree-ssa/builtin-sprintf-28.c: New test.
	* gcc.dg/tree-ssa/builtin-sprintf-29.c: New test.
	* gcc.dg/uninit-pr100732.c: New test.

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 68717cf1542..0a80908711c 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -3509,10 +3509,6 @@ bool
 gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
 {
   gimple *stmt = gsi_stmt (*gsi);
-  tree dest = gimple_call_arg (stmt, 0);
-  tree fmt = gimple_call_arg (stmt, 1);
-  tree orig = NULL_TREE;
-  const char *fmt_str = NULL;
 
   /* Verify the required arguments in the original call.  We deal with two
      types of sprintf() calls: 'sprintf (str, fmt)' and
@@ -3520,25 +3516,28 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
   if (gimple_call_num_args (stmt) > 3)
     return false;
 
+  tree orig = NULL_TREE;
   if (gimple_call_num_args (stmt) == 3)
     orig = gimple_call_arg (stmt, 2);
 
   /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
+  tree fmt = gimple_call_arg (stmt, 1);
+  const char *fmt_str = c_getstr (fmt);
   if (fmt_str == NULL)
     return false;
 
+  tree dest = gimple_call_arg (stmt, 0);
+
   if (!init_target_chars ())
     return false;
 
+  tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+  if (!fn)
+    return false;
+
   /* If the format doesn't contain % args or %%, use strcpy.  */
   if (strchr (fmt_str, target_percent) == NULL)
     {
-      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-
-      if (!fn)
-	return false;
-
       /* Don't optimize sprintf (buf, "abc", ptr++).  */
       if (orig)
 	return false;
@@ -3579,16 +3578,15 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
   /* If the format is "%s", use strcpy if the result isn't used.  */
   else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
     {
-      tree fn;
-      fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-
-      if (!fn)
-	return false;
-
       /* Don't crash on sprintf (str1, "%s").  */
       if (!orig)
 	return false;
 
+      /* Don't fold calls with source arguments of invalid (nonpointer)
+	 types.  */
+      if (!POINTER_TYPE_P (TREE_TYPE (orig)))
+	return false;
+
       tree orig_len = NULL_TREE;
       if (gimple_call_lhs (stmt))
 	{
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-11.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-11.c
new file mode 100644
index 00000000000..73117c49a73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-11.c
@@ -0,0 +1,32 @@
+/* PR middle-end/100732 - ICE on sprintf %s with integer argument
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+char d[32];
+
+void gb (_Bool b)
+{
+  __builtin_snprintf (d, 32, "%s", b);  // { dg-warning "\\\[-Wformat" }
+}
+
+void gi (int i)
+{
+  __builtin_snprintf (d, 32, "%s", i);  // { dg-warning "\\\[-Wformat" }
+}
+
+void gd (char *d, double x)
+{
+  __builtin_snprintf (d, 32, "%s", x);  // { dg-warning "\\\[-Wformat" }
+}
+
+
+struct X { int i; };
+
+void gx (char *d, struct X x)
+{
+  __builtin_snprintf (d, 32, "%s", x);  // { dg-warning "\\\[-Wformat" }
+}
+
+/* Also verify that the invalid sprintf call isn't folded to strcpy.
+   { dg-final { scan-tree-dump-times "snprintf" 4 "optimized" } }
+   { dg-final { scan-tree-dump-not "strcpy" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-12.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-12.c
new file mode 100644
index 00000000000..9e263568c1b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-12.c
@@ -0,0 +1,36 @@
+/* PR middle-end/100732 - ICE on sprintf %s with integer argument
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+#define snprintf(d, n, f, ...)					\
+  __builtin___snprintf_chk (d, n, 0, 32, f, __VA_ARGS__)
+
+int n;
+
+void gb (char *d, _Bool b)
+{
+  snprintf (d, n, "%s", b);  // { dg-warning "\\\[-Wformat" }
+}
+
+void gi (char *d, int i)
+{
+  snprintf (d, n, "%s", i);  // { dg-warning "\\\[-Wformat" }
+}
+
+void gd (char *d, double x)
+{
+  snprintf (d, n, "%s", x);  // { dg-warning "\\\[-Wformat" }
+}
+
+
+struct X { int i; };
+
+void gx (char *d, struct X x)
+{
+  snprintf (d, n, "%s", x);  // { dg-warning "\\\[-Wformat" }
+}
+
+
+/* Also verify that the invalid sprintf call isn't folded to strcpy.
+   { dg-final { scan-tree-dump-times "snprintf_chk" 4 "optimized" } }
+   { dg-final { scan-tree-dump-not "strcpy" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-28.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-28.c
new file mode 100644
index 00000000000..c1d0083506f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-28.c
@@ -0,0 +1,30 @@
+/* PR middle-end/100732 - ICE on sprintf %s with integer argument
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+void gb (char *d, _Bool b)
+{
+  __builtin_sprintf (d, "%s", b);       // { dg-warning "\\\[-Wformat" }
+}
+
+void gi (char *d, int i)
+{
+  __builtin_sprintf (d, "%s", i);       // { dg-warning "\\\[-Wformat" }
+}
+
+void gd (char *d, double x)
+{
+  __builtin_sprintf (d, "%s", x);       // { dg-warning "\\\[-Wformat" }
+}
+
+
+struct X { int i; };
+
+void gx (char *d, struct X x)
+{
+  __builtin_sprintf (d, "%s", x);       // { dg-warning "\\\[-Wformat" }
+}
+
+/* Also verify that the invalid sprintf call isn't folded to strcpy.
+   { dg-final { scan-tree-dump-times "sprintf" 4 "optimized" } }
+   { dg-final { scan-tree-dump-not "strcpy" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-29.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-29.c
new file mode 100644
index 00000000000..d0f7db26391
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-29.c
@@ -0,0 +1,40 @@
+/* PR middle-end/100732 - ICE on sprintf %s with integer argument
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+#define sprintf(d, f, ...) \
+  __builtin___sprintf_chk (d, 0, 32, f, __VA_ARGS__)
+
+
+void fi (int i, const char *s)
+{
+  sprintf (i, "%s", s);       // { dg-warning "\\\[-Wint-conversion" }
+}
+
+void gb (char *d, _Bool b)
+{
+  sprintf (d, "%s", b);       // { dg-warning "\\\[-Wformat" }
+}
+
+void gi (char *d, int i)
+{
+  sprintf (d, "%s", i);       // { dg-warning "\\\[-Wformat" }
+}
+
+void gd (char *d, double x)
+{
+  sprintf (d, "%s", x);       // { dg-warning "\\\[-Wformat" }
+}
+
+
+struct X { int i; };
+
+void gx (char *d, struct X x)
+{
+  sprintf (d, "%s", x);       // { dg-warning "\\\[-Wformat" }
+}
+
+
+/* Also verify that the invalid sprintf call isn't folded to strcpy.
+   { dg-final { scan-tree-dump-times "sprintf_chk" 5 "optimized" } }
+   { dg-final { scan-tree-dump-not "strcpy" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/uninit-pr100732.c b/gcc/testsuite/gcc.dg/uninit-pr100732.c
new file mode 100644
index 00000000000..9c847ce1fa8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pr100732.c
@@ -0,0 +1,21 @@
+/* PR middle-end/100732 - ICE on sprintf %s with integer argument
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+void nowarn_s_i (char *d, int i)
+{
+  __builtin_sprintf (d, "%s", i);       // { dg-warning "\\\[-Wformat" }
+}
+
+void warn_s_i (char *d)
+{
+  int i;
+  __builtin_sprintf (d, "%s", i);       // { dg-warning "\\\[-Wformat" }
+                                        // { dg-warning "\\\[-Wuninitialized" "" { target *-*-* } .-1 }
+}
+
+void warn_i_i (char *d)
+{
+  int i;
+  __builtin_sprintf (d, "%i", i);       // { dg-warning "\\\[-Wuninitialized" }
+}
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index f55ce1939ac..8a5aa0f9254 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -540,6 +540,9 @@ maybe_warn_pass_by_reference (gcall *stmt, wlimits &wlims)
 	continue;
 
       tree arg = gimple_call_arg (stmt, argno - 1);
+      if (!POINTER_TYPE_P (TREE_TYPE (arg)))
+	/* Avoid actual arguments with invalid types.  */
+	continue;
 
       ao_ref ref;
       ao_ref_init_from_ptr_and_size (&ref, arg, access_size);

Reply via email to