Attached is yet another patch to avoid ICE due to middle-end assumptions about the sanity of calls to built-ins, this time for strnlen. It fixes two unsafe assumptions:
1) The -Wstringop-overflow checker for unterminated constant char arrays assumes that strnlen is called with exactly two arguments. When the function is declared without a prototype and called with no arguments the code aborts. This is PR 89911 (P1). 2) The wide_int min/max values of get_range_info() called on the strnlen bound have the same precision as PTRDIFF_MAX. That's not so when strnlen is declared without a prototype and called with an int128_t argument in some range. Rather than handling this case, wi::ltu_p() helpfully aborts instead. This is PR 89957 that I exposed while testing the fix above. The trivial patch avoids both of these assumptions. It's been tested on x86_64-linux. Similar to the patch for PR 89934, I will commit it later this week unless there are objections. Martin Patch for PR 89934 for reference: https://gcc.gnu.org/ml/gcc-patches/2019-04/msg00149.html
PR middle-end/89957 - ICE calling strnlen with an int128_t bound in a known range PR middle-end/89911 - [9 Regression] ICE in get_attr_nonstring_decl gcc/ChangeLog: PR middle-end/89957 PR middle-end/89911 * builtins.c (expand_builtin_strnlen): Make sure wi::ltu_p operands have the same precision since the function crashes otherwise. * calls.c (maybe_warn_nonstring_arg): Avoid assuming strnlen() call has non-zero arguments. gcc/testsuite/ChangeLog: PR middle-end/89957 PR middle-end/89911 * gcc.dg/Wstringop-overflow-13.c: New test. Index: gcc/builtins.c =================================================================== --- gcc/builtins.c (revision 270149) +++ gcc/builtins.c (working copy) @@ -3151,7 +3151,7 @@ expand_builtin_strnlen (tree exp, rtx target, mach return NULL_RTX; if (!TREE_NO_WARNING (exp) - && wi::ltu_p (wi::to_wide (maxobjsize), min) + && wi::ltu_p (wi::to_wide (maxobjsize, min.get_precision ()), min) && warning_at (loc, OPT_Wstringop_overflow_, "%K%qD specified bound [%wu, %wu] " "exceeds maximum object size %E", Index: gcc/calls.c =================================================================== --- gcc/calls.c (revision 270149) +++ gcc/calls.c (working copy) @@ -1555,7 +1555,10 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) if (TREE_NO_WARNING (exp) || !warn_stringop_overflow) return; + /* Avoid clearly invalid calls (more checking done below). */ unsigned nargs = call_expr_nargs (exp); + if (!nargs) + return; /* The bound argument to a bounded string function like strncpy. */ tree bound = NULL_TREE; Index: gcc/testsuite/gcc.dg/Wstringop-overflow-13.c =================================================================== --- gcc/testsuite/gcc.dg/Wstringop-overflow-13.c (nonexistent) +++ gcc/testsuite/gcc.dg/Wstringop-overflow-13.c (working copy) @@ -0,0 +1,40 @@ +/* PR middle-end/89957 - ICE calling strnlen with an int128_t bound + in a known range + PR middle-end/89911 - ICE on a call with no arguments to strnlen + declared with no prototype + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +extern size_t strnlen (); + +size_t f0 (void) +{ + return strnlen (); /* { dg-warning "too few arguments to built-in function 'strnlen'" } */ +} + +size_t f1 (const char *s) +{ + return strnlen (s); /* { dg-warning "too few arguments to built-in function 'strnlen'" } */ +} + +size_t f2 (const char *s) +{ + return strnlen (s, s); /* { dg-warning "\\\[-Wint-conversion]" } */ +} + +#if __SIZEOF_INT128__ == 16 + +size_t fi128 (const char *s, __int128_t n) +{ + if (n < 0) + n = 0; + + /* PR middle-end/89957 */ + return strnlen (s, n); /* { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" "int128" { target int128 } } */ +} + +#endif + +/* { dg-prune-output "\\\[-Wint-conversion]" } */