The -Wformat-overflow warning newly enhanced in GCC 8.0 to detect reading past the end of the source sequence misinterprets the size argument to stpncpy as a request to read that many bytes from the source sequence, rather than the number of bytes to write. Like strncpy, the function never reads past the end of the source string.
This constraint is already handled correctly for strncpy by the check_sizes function so the fix is to simply remove the wrong length handling from expand_builtin_stpncpy and let check_sizes do the right thing. The attached patch passes bootstrap and regression test on x86_64. Martin
PR middle-end/80669 - Bad -Wstringop-overflow warnings for stpncpy gcc/ChangeLog: PR middle-end/80669 * builtins.c (expand_builtin_stpncpy): Simplify. gcc/testsuite/ChangeLog: PR middle-end/80669 * gcc.dg/builtin-stpncpy.c: New test. diff --git a/gcc/builtins.c b/gcc/builtins.c index 936fcee..4f6c9c4 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3788,31 +3788,18 @@ expand_builtin_stpncpy (tree exp, rtx) || !warn_stringop_overflow) return NULL_RTX; + /* The source and destination of the call. */ tree dest = CALL_EXPR_ARG (exp, 0); tree src = CALL_EXPR_ARG (exp, 1); - /* The number of bytes to write (not the maximum). */ + /* The exact number of bytes to write (not the maximum). */ tree len = CALL_EXPR_ARG (exp, 2); - /* The length of the source sequence. */ - tree slen = c_strlen (src, 1); - - /* Try to determine the range of lengths that the source expression - refers to. */ - tree lenrange[2]; - if (slen) - lenrange[0] = lenrange[1] = slen; - else - { - get_range_strlen (src, lenrange); - slen = lenrange[0]; - } + /* The size of the destination object. */ tree destsize = compute_objsize (dest, warn_stringop_overflow - 1); - /* The number of bytes to write is LEN but check_sizes will also - check SLEN if LEN's value isn't known. */ check_sizes (OPT_Wstringop_overflow_, - exp, len, /*maxlen=*/NULL_TREE, slen, destsize); + exp, len, /*maxlen=*/NULL_TREE, src, destsize); return NULL_RTX; } diff --git a/gcc/testsuite/gcc.dg/builtin-stpncpy.c b/gcc/testsuite/gcc.dg/builtin-stpncpy.c new file mode 100644 index 0000000..e4290d5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-stpncpy.c @@ -0,0 +1,74 @@ +/* PR tree-optimization/80669 - Bad -Wstringop-overflow warnings for stpncpy + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +#define SIZE_MAX __SIZE_MAX__ + +typedef __SIZE_TYPE__ size_t; + +void sink (char*); + +#define stpncpy (d, s, n) sink (__builtin_stpncpy (d, s, n)) + +size_t value (void); + +size_t range (size_t min, size_t max) +{ + size_t val = value (); + return val < min || max < val ? min : val; +} + +/* Verify that no warning is issued for stpncpy with constant size. */ +void test_cst (char *d) +{ + __builtin_stpncpy (d, "123", 0); + __builtin_stpncpy (d, "123", 1); + __builtin_stpncpy (d, "123", 2); + __builtin_stpncpy (d, "123", 3); + __builtin_stpncpy (d, "123", 4); + __builtin_stpncpy (d, "123", 5); + __builtin_stpncpy (d, "123", 999); + + size_t n = SIZE_MAX / 2; + + __builtin_stpncpy (d, "123", n); + + __builtin_stpncpy (d, "123", n + 1); /* { dg-warning "specified size \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ +} + + +/* Verify that no warning is issued for stpncpy with size in some range. */ +void test_rng (char *d) +{ +#define R(min, max) range (min, max) + + __builtin_stpncpy (d, "123", R (0, 1)); + __builtin_stpncpy (d, "123", R (0, 2)); + __builtin_stpncpy (d, "123", R (0, 3)); + __builtin_stpncpy (d, "123", R (0, 4)); + __builtin_stpncpy (d, "123", R (0, 5)); + + __builtin_stpncpy (d, "123", R (1, 2)); + __builtin_stpncpy (d, "123", R (1, 3)); + __builtin_stpncpy (d, "123", R (1, 4)); + __builtin_stpncpy (d, "123", R (1, 5)); + + __builtin_stpncpy (d, "123", R (2, 3)); + __builtin_stpncpy (d, "123", R (2, 4)); + __builtin_stpncpy (d, "123", R (2, 5)); + + __builtin_stpncpy (d, "123", R (3, 4)); + __builtin_stpncpy (d, "123", R (3, 5)); + + __builtin_stpncpy (d, "123", R (4, 5)); + + __builtin_stpncpy (d, "123", R (5, 6)); + + __builtin_stpncpy (d, "123", R (12345, 23456)); + + size_t n = SIZE_MAX / 2; + + __builtin_stpncpy (d, "123", R (n - 1, n + 1)); + + __builtin_stpncpy (d, "123", R (n + 1, n + 2)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ +}