The -Wrestrict code assumes that built-ins are called with the correct number of arguments. When this isn't so it crashes. The attached patch avoids the ICE due to this error.
There are outstanding assumptions that the type of actual arguments to built-ins declared without a prototype matches the expected type. Those will be corrected in a subsequent patch. Martin
PR tree-optimization/83603 - ICE in builtin_memref at gcc/gimple-ssa-warn-restrict.c:238 gcc/ChangeLog: PR tree-optimization/83603 * calls.c (maybe_warn_nonstring_arg): Avoid accessing function arguments past the endof the argument list in functions declared without a prototype. * gimple-ssa-warn-restrict.c (wrestrict_dom_walker::check_call): Avoid checking when arguments are null. diff --git a/gcc/calls.c b/gcc/calls.c index 9b7e118..0cfc20a 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1606,6 +1606,8 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) bool with_bounds = CALL_WITH_BOUNDS_P (exp); + unsigned nargs = call_expr_nargs (exp); + /* The bound argument to a bounded string function like strncpy. */ tree bound = NULL_TREE; @@ -1620,12 +1622,20 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) case BUILT_IN_STRNCASECMP: case BUILT_IN_STRNCPY: case BUILT_IN_STRNCPY_CHK: - bound = CALL_EXPR_ARG (exp, with_bounds ? 4 : 2); - break; + { + unsigned argno = with_bounds ? 4 : 2; + if (argno < nargs) + bound = CALL_EXPR_ARG (exp, argno); + break; + } case BUILT_IN_STRNDUP: - bound = CALL_EXPR_ARG (exp, with_bounds ? 2 : 1); - break; + { + unsigned argno = with_bounds ? 2 : 1; + if (argno < nargs) + bound = CALL_EXPR_ARG (exp, argno); + break; + } default: break; @@ -1645,6 +1655,11 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) for (unsigned argno = 0; ; ++argno, function_args_iter_next (&it)) { + /* Avoid iterating past the declared argument in a call + to function declared without a prototype. */ + if (argno >= nargs) + break; + tree argtype = function_args_iter_cond (&it); if (!argtype) break; diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index ebec381..a2a29cd 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -1710,7 +1710,9 @@ wrestrict_dom_walker::check_call (gcall *call) if (!dstwr && strfun) dstwr = size_one_node; - if (check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE)) + /* DST and SRC can be null for a call with an insufficient number + of arguments to a built-in function declared without a protype. */ + if (!dst || !src || check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE)) return; /* Avoid diagnosing the call again. */ diff --git a/gcc/testsuite/gcc.dg/Wrestrict-4.c b/gcc/testsuite/gcc.dg/Wrestrict-4.c new file mode 100644 index 0000000..f2398ef --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wrestrict-4.c @@ -0,0 +1,110 @@ +/* PR tree-optimization/83603 - ICE in builtin_memref at + gcc/gimple-ssa-warn-restrict.c:238 + Test to verify that invalid calls to built-in functions declared + without a prototype don't cause an ICE. + { dg-do compile } + { dg-options "-O2 -Warray-bounds -Wrestrict" } */ + +void* memcpy (); +void* memmove (); +char* stpcpy (); +char* strcat (); +char* strcpy (); +char* strncat (); +char* strncpy (); + +void* test_memcpy_0 () +{ + return memcpy (); +} + +void* test_memcpy_1 (void *d) +{ + return memcpy (d); +} + +void* test_memcpy_2 (void *d, const void *s) +{ + return memcpy (d, s); +} + + +void* test_memmove_0 () +{ + return memmove (); +} + +void* test_memmove_1 (void *d) +{ + return memmove (d); +} + +void* test_memmove_2 (void *d, const void *s) +{ + return memmove (d, s); +} + + +void* test_stpcpy_0 () +{ + return stpcpy (); +} + +void* test_stpcpy_1 (char *d) +{ + return stpcpy (d); +} + + +char* test_strcat_0 () +{ + return strcat (); +} + +char* test_strcat_1 (char *d) +{ + return strcat (d); +} + + +void* test_strcpy_0 () +{ + return strcpy (); +} + +void* test_strcpy_1 (char *d) +{ + return strcpy (d); +} + + +char* test_strncat_0 () +{ + return strncat (); +} + +char* test_strncat_1 (char *d) +{ + return strncat (d); +} + +char* test_strncat_2 (char *d, const char *s) +{ + return strncat (d, s); +} + + +void* test_strncpy_0 () +{ + return strncpy (); +} + +void* test_strncpy_1 (char *d) +{ + return strncpy (d); +} + +void* test_strncpy_2 (char *d, const char *s) +{ + return strncpy (d, s); +}