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);