From bf00c9e08002fcb36d8b61d2e2a47801ef11c2f1 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 14 Feb 2017 16:51:24 +0000 Subject: [PATCH] PR middle-end/79448 - unhelpful -Wformat-truncation=2 warning gcc/testsuite/ChangeLog: PR middle-end/79448 * gcc.dg/tree-ssa/builtin-snprintf-warn-3.c: New test. * gcc.dg/tree-ssa/pr79448-2.c: New test. * gcc.dg/tree-ssa/pr79448.c: New test. gcc/ChangeLog: PR middle-end/79448 * gimple-ssa-sprintf.c (format_directive): Avoid issuing INT_MAX warning for strings of unknown length. From-SVN: r245437 --- gcc/ChangeLog | 6 + gcc/gimple-ssa-sprintf.c | 14 +- gcc/testsuite/ChangeLog | 7 + .../gcc.dg/tree-ssa/builtin-snprintf-warn-3.c | 193 ++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr79448-2.c | 21 ++ gcc/testsuite/gcc.dg/tree-ssa/pr79448.c | 21 ++ 6 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr79448-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr79448.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bd6fdb48012..3d0e95e29d2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2017-02-14 Martin Sebor + + PR middle-end/79448 + * gimple-ssa-sprintf.c (format_directive): Avoid issuing INT_MAX + warning for strings of unknown length. + 2017-02-13 Segher Boessenkool * config.gcc (supported_defaults) [powerpc*-*-*]: Update. diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index b2db8b848b0..a5fc3ffd725 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -2559,13 +2559,16 @@ format_directive (const pass_sprintf_length::call_info &info, res->range.max += fmtres.range.max; /* Raise the total unlikely maximum by the larger of the maximum - and the unlikely maximum. It doesn't matter if the unlikely - maximum overflows. */ + and the unlikely maximum. */ + unsigned HOST_WIDE_INT save = res->range.unlikely; if (fmtres.range.max < fmtres.range.unlikely) res->range.unlikely += fmtres.range.unlikely; else res->range.unlikely += fmtres.range.max; + if (res->range.unlikely < save) + res->range.unlikely = HOST_WIDE_INT_M1U; + res->range.min += fmtres.range.min; res->range.likely += fmtres.range.likely; @@ -2616,7 +2619,12 @@ format_directive (const pass_sprintf_length::call_info &info, /* Has the likely and maximum directive output exceeded INT_MAX? */ bool likelyximax = *dir.beg && res->range.likely > target_int_max (); - bool maxximax = *dir.beg && res->range.max > target_int_max (); + /* Don't consider the maximum to be in excess when it's the result + of a string of unknown length (i.e., whose maximum has been set + to be greater than or equal to HOST_WIDE_INT_MAX. */ + bool maxximax = (*dir.beg + && res->range.max > target_int_max () + && res->range.max < HOST_WIDE_INT_MAX); if (!warned /* Warn for the likely output size at level 1. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fb5b69d4298..6e42393e995 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-02-14 Martin Sebor + + PR middle-end/79448 + * gcc.dg/tree-ssa/builtin-snprintf-warn-3.c: New test. + * gcc.dg/tree-ssa/pr79448-2.c: New test. + * gcc.dg/tree-ssa/pr79448.c: New test. + 2017-02-14 Jeff Law PR tree-optimization/79095 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c new file mode 100644 index 00000000000..81c1d893e35 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c @@ -0,0 +1,193 @@ +/* PR middle-end/79448 - unhelpful -Wformat-truncation=2 warning + { dg-do compile } + { dg-options "-O2 -Wformat -Wformat-truncation=2 -ftrack-macro-expansion=0" } */ + +typedef __SIZE_TYPE__ size_t; +typedef __WCHAR_TYPE__ wchar_t; + +#define INT_MAX __INT_MAX__ +#define INT_MIN (-INT_MAX - 1) + +/* When debugging, define LINE to the line number of the test case to exercise + and avoid exercising any of the others. The buffer and objsize macros + below make use of LINE to avoid warnings for other lines. */ +#ifndef LINE +# define LINE 0 +#endif + +extern int int_value (void); +extern size_t size_value (void); + +int int_range (int min, int max) +{ + int n = int_value (); + return n < min || max < n ? min : n; +} + +void sink (int, char*, char*); + +int dummy_snprintf (char*, size_t, const char*, ...); + +char fixed_buffer [256]; +extern char *unknown_buffer; +extern size_t unknown_size; + +/* Helper to expand function to either __builtin_f or dummy_f to + make debugging GCC easy. */ +#define FUNC(f) \ + ((!LINE || LINE == __LINE__) ? __builtin_ ## f : dummy_ ## f) + +/* Helper test macro. */ +#define T(size, ...) \ + do { \ + size_t n = size < 0 ? unknown_size : size; \ + char *buf = size < 0 ? unknown_buffer \ + : n < sizeof fixed_buffer \ + ? fixed_buffer + sizeof fixed_buffer - size \ + : unknown_buffer; \ + FUNC (snprintf) (buf, n, __VA_ARGS__); \ + sink (0, fixed_buffer, unknown_buffer); \ + } while (0) + +/* Return a value in the range [MIN, MAX]. */ +#define IR(min, max) int_range (min, max) + +struct Arrays +{ + char a1[1]; + char a4k[4096]; + char a4kp1[4097]; +#if INT_MAX < LONG_MAX + char amax[INT_MAX]; +#else + char amax[32767]; +#endif + char ax[]; +}; + +void test_string_unchecked (const char *s, const struct Arrays *ar) +{ + /* Verify there is no warning with strings of unknown length. */ + T (-1, "%-s", s); + T (-1, "%-s", ar->ax); + + T (-1, "%s%s", s, s); + T (-1, "%s%s", "", s); + T (-1, "%s%s", s, "1"); + T (-1, "%s%s", "1", s); + + /* Verify there is no warning with strings of length that cannot + exceed 4k (because of the array size). */ + T (-1, "%-s", ar->a1); + T (-1, "%-s", ar->a4k); + + /* Verify there's no "exceeds minimum required size of 4095" warning + with multiple %s directives and a combination of strings of unknown + (and potentially unbounded) length and strings whose length is + bounded by the size of the arrays they are stored in. */ + T (-1, "%s%s", s, ar->a4k); + T (-1, "%s%s", ar->a4k, s); + T (-1, "%s%s", ar->a4k, ar->a4k); + T (-1, "%s%s", ar->a4k, "123"); + T (-1, "%s%s", "123", ar->a4k); + T (-1, "%s%s", ar->ax, ar->a4k); + T (-1, "%s%s", ar->a4k, ar->ax); + + /* Verify that an array that fits a string longer than 4095 bytes + does trigger a warning. */ + T (-1, "%-s", ar->a4kp1); /* { dg-warning "directive output between 0 and 4096 bytes may exceed minimum required size of 4095" } */ + + /* Also verify that a %s directive with width greater than 4095 + triggers a warning even if the argument is not longer than 4k. */ + T (-1, "%*s", 4096, ar->a4k); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + + /* Verify that precision constrains the putput and suppresses the 4k + warning. */ + T (-1, "%.*s", 4095, ar->a4kp1); + + T (-1, "%s %s", s, ""); + T (-1, "%s %s", "", s); + T (-1, "%s %s", s, "1"); + T (-1, "%s %s", "1", s); + + T (-1, "%s%s%s", s, "1", s); + T (-1, "%s%s%s", "1", s, "1"); + T (-1, "%s%s%s", s, s, s); + T (-1, "%*s%*s%*s", 4093, s, 4094, s, 4095, s); + T (-1, "%s %s %s", s, s, s); + T (-1, "%s %s %s", ar->a4k, ar->a4k, ar->a4k); + T (-1, "%s %s %s", ar->ax, ar->ax, ar->ax); + + /* Verify that an array of INT_MAX elements doesn't trigger the INT_MAX + warning (LP64 only). */ + T (-1, "%-s", ar->amax); /* { dg-warning "directive output between 0 and \[0-9\]+ bytes may exceed minimum required size of 4095" } */ +} + +#undef T +/* Helper test macro. */ +#define T(size, ...) \ + do { \ + size_t n = size < 0 ? unknown_size : size; \ + char *buf = size < 0 ? unknown_buffer \ + : n < sizeof fixed_buffer \ + ? fixed_buffer + sizeof fixed_buffer - size \ + : unknown_buffer; \ + int r = FUNC (snprintf) (buf, n, __VA_ARGS__); \ + sink (r, fixed_buffer, unknown_buffer); \ + } while (0) + +void test_string_checked (const char *s, const struct Arrays *ar) +{ + /* Verify there is no warning with strings of unknown length. */ + T (-1, "%-s", s); + T (-1, "%-s", ar->ax); + + T (-1, "%s%s", s, s); + T (-1, "%s%s", "", s); + T (-1, "%s%s", s, "1"); + T (-1, "%s%s", "1", s); + + /* Verify there is no warning with strings of length that cannot + exceed 4k (because of the array size). */ + T (-1, "%-s", ar->a1); + T (-1, "%-s", ar->a4k); + + /* Verify there's no "exceeds minimum required size of 4095" warning + with multiple %s directives and a combination of strings of unknown + (and potentially unbounded) length and strings whose length is + bounded by the size of the arrays they are stored in. */ + T (-1, "%s%s", s, ar->a4k); + T (-1, "%s%s", ar->a4k, s); + T (-1, "%s%s", ar->a4k, ar->a4k); + T (-1, "%s%s", ar->a4k, "123"); + T (-1, "%s%s", "123", ar->a4k); + T (-1, "%s%s", ar->ax, ar->a4k); + T (-1, "%s%s", ar->a4k, ar->ax); + + /* Verify that an array that fits a string longer than 4095 bytes + does trigger a warning. */ + T (-1, "%-s", ar->a4kp1); /* { dg-warning "directive output between 0 and 4096 bytes may exceed minimum required size of 4095" } */ + + /* Also verify that a %s directive with width greater than 4095 + triggers a warning even if the argument is not longer than 4k. */ + T (-1, "%*s", 4096, ar->a4k); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + + /* Verify that precision constrains the putput and suppresses the 4k + warning. */ + T (-1, "%.*s", 4095, ar->a4kp1); + + T (-1, "%s %s", s, ""); + T (-1, "%s %s", "", s); + T (-1, "%s %s", s, "1"); + T (-1, "%s %s", "1", s); + + T (-1, "%s%s%s", s, "1", s); + T (-1, "%s%s%s", "1", s, "1"); + T (-1, "%s%s%s", s, s, s); + T (-1, "%*s%*s%*s", 4093, s, 4094, s, 4095, s); + T (-1, "%s %s %s", s, s, s); + T (-1, "%s %s %s", ar->a4k, ar->a4k, ar->a4k); + T (-1, "%s %s %s", ar->ax, ar->ax, ar->ax); + + T (-1, "%-s", ar->amax); /* { dg-warning "directive output between 0 and \[0-9\]+ bytes may exceed minimum required size of 4095" } */ +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr79448-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr79448-2.c new file mode 100644 index 00000000000..f75f523a2e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr79448-2.c @@ -0,0 +1,21 @@ +/* PR middle-end/79448 - unhelpful -Wformat-truncation=2 warning + Verify that there's no warning with optimization. + { dg-do compile } + { dg-options "-O2 -Wall -Wformat -Wformat-truncation=2" } */ + +typedef __SIZE_TYPE__ size_t; + +extern int +snprintf (char*, size_t, const char*, ...); + +char* +gettext (char*); + +char* +fill (char *buf, size_t len, int count) +{ + if (snprintf (buf, len, "%s: %d", gettext ("count"), count) >= len) /* { dg-bogus "directive output of 2 bytes causes result to exceed .INT_MAX." */ + return 0; + + return buf; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr79448.c b/gcc/testsuite/gcc.dg/tree-ssa/pr79448.c new file mode 100644 index 00000000000..c346c9ef08a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr79448.c @@ -0,0 +1,21 @@ +/* PR middle-end/79448 - unhelpful -Wformat-truncation=2 warning + Verify that there's no warning without optimization. + { dg-do compile } + { dg-options "-Wall -Wformat -Wformat-truncation=2" } */ + +typedef __SIZE_TYPE__ size_t; + +extern int +snprintf (char*, size_t, const char*, ...); + +char* +gettext (char*); + +char* +fill (char *buf, size_t len, int count) +{ + if (snprintf (buf, len, "%s: %d", gettext ("count"), count) >= len) /* { dg-bogus "directive output of 2 bytes causes result to exceed .INT_MAX." */ + return 0; + + return buf; +} -- 2.30.2