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
This commit is contained in:
Martin Sebor 2017-02-14 16:51:24 +00:00 committed by Martin Sebor
parent 355930ab26
commit bf00c9e080
6 changed files with 259 additions and 3 deletions

View File

@ -1,3 +1,9 @@
2017-02-14 Martin Sebor <msebor@redhat.com>
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 <segher@kernel.crashing.org>
* config.gcc (supported_defaults) [powerpc*-*-*]: Update.

View File

@ -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. */

View File

@ -1,3 +1,10 @@
2017-02-14 Martin Sebor <msebor@redhat.com>
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 <law@redhat.com>
PR tree-optimization/79095

View File

@ -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" } */
}

View File

@ -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;
}

View File

@ -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;
}