PR tree-optimization/88993 - GCC 9 -Wformat-overflow=2 should reflect real libc limits
PR tree-optimization/88835 - overly aggressive -Werror=format-overflow for printf
gcc/ChangeLog:
PR tree-optimization/88993
PR tree-optimization/88853
* gimple-ssa-sprintf.c (sprintf_dom_walker::call_info::is_file_func):
New helper.
(sprintf_dom_walker::call_info::is_string_func): New helper.
(format_directive): Only issue "may exceed" 4095/INT_MAX warnings
for formatted string functions.
(sprintf_dom_walker::handle_gimple_call): Fix a typo in a comment.
gcc/testsuite/ChangeLog:
PR tree-optimization/88993
PR tree-optimization/88853
* gcc.dg/tree-ssa/builtin-fprintf-warn-2.c: New test.
* gcc.dg/tree-ssa/builtin-printf-warn-2.c: New test.
* gcc.dg/tree-ssa/builtin-snprintf-warn-3.c: Adjust.
* gcc.dg/tree-ssa/builtin-sprintf-warn-18.c: Same.
From-SVN: r269125
{
return bounded ? OPT_Wformat_truncation_ : OPT_Wformat_overflow_;
}
+
+ /* Return true for calls to file formatted functions. */
+ bool is_file_func () const
+ {
+ return (fncode == BUILT_IN_FPRINTF
+ || fncode == BUILT_IN_FPRINTF_CHK
+ || fncode == BUILT_IN_FPRINTF_UNLOCKED
+ || fncode == BUILT_IN_VFPRINTF
+ || fncode == BUILT_IN_VFPRINTF_CHK);
+ }
+
+ /* Return true for calls to string formatted functions. */
+ bool is_string_func () const
+ {
+ return (fncode == BUILT_IN_SPRINTF
+ || fncode == BUILT_IN_SPRINTF_CHK
+ || fncode == BUILT_IN_SNPRINTF
+ || fncode == BUILT_IN_SNPRINTF_CHK
+ || fncode == BUILT_IN_VSPRINTF
+ || fncode == BUILT_IN_VSPRINTF_CHK
+ || fncode == BUILT_IN_VSNPRINTF
+ || fncode == BUILT_IN_VSNPRINTF_CHK);
+ }
};
/* Return the result of formatting a no-op directive (such as '%n'). */
if (!warned
/* Only warn at level 2. */
&& warn_level > 1
+ /* Only warn for string functions. */
+ && info.is_string_func ()
&& (!minunder4k
|| (!maxunder4k && fmtres.range.max < HOST_WIDE_INT_MAX)))
{
of C11. Warn on this only at level 2 but remember this and
prevent folding the return value when done. This allows for
the possibility of the actual libc call failing due to ENOMEM
- (like Glibc does under some conditions). */
+ (like Glibc does with very large precision or width).
+ Issue the "may exceed" warning only for string functions and
+ not for fprintf or printf. */
if (fmtres.range.min == fmtres.range.max)
warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
"minimum required size of 4095", dirlen,
target_to_host (hostdir, sizeof hostdir, dir.beg),
fmtres.range.min);
- else
+ else if (!minunder4k)
+ warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
+ "%<%.*s%> directive output between %wu and %wu "
+ "bytes exceeds minimum required size of 4095",
+ dirlen,
+ target_to_host (hostdir, sizeof hostdir, dir.beg),
+ fmtres.range.min, fmtres.range.max);
+ else if (!info.retval_used () && info.is_string_func ())
warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- minunder4k
- ? G_("%<%.*s%> directive output between %wu and %wu "
- "bytes may exceed minimum required size of "
- "4095")
- : G_("%<%.*s%> directive output between %wu and %wu "
- "bytes exceeds minimum required size of 4095"),
+ "%<%.*s%> directive output between %wu and %wu "
+ "bytes may exceed minimum required size of "
+ "4095",
dirlen,
target_to_host (hostdir, sizeof hostdir, dir.beg),
fmtres.range.min, fmtres.range.max);
&& maxximax
&& fmtres.range.max < HOST_WIDE_INT_MAX)))
{
- /* The directive output causes the total length of output
- to exceed INT_MAX bytes. */
-
- if (fmtres.range.min == fmtres.range.max)
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output of %wu bytes causes "
- "result to exceed %<INT_MAX%>", dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min);
- else
+ if (fmtres.range.min > target_int_max ())
+ {
+ /* The directive output exceeds INT_MAX bytes. */
+ if (fmtres.range.min == fmtres.range.max)
+ warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
+ "%<%.*s%> directive output of %wu bytes exceeds "
+ "%<INT_MAX%>", dirlen,
+ target_to_host (hostdir, sizeof hostdir, dir.beg),
+ fmtres.range.min);
+ else
+ warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
+ "%<%.*s%> directive output between %wu and "
+ "%wu bytes exceeds %<INT_MAX%>", dirlen,
+ target_to_host (hostdir, sizeof hostdir, dir.beg),
+ fmtres.range.min, fmtres.range.max);
+ }
+ else if (res->range.min > target_int_max ())
+ {
+ /* The directive output is under INT_MAX but causes the result
+ to exceed INT_MAX bytes. */
+ if (fmtres.range.min == fmtres.range.max)
+ warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
+ "%<%.*s%> directive output of %wu bytes causes "
+ "result to exceed %<INT_MAX%>", dirlen,
+ target_to_host (hostdir, sizeof hostdir, dir.beg),
+ fmtres.range.min);
+ else
+ warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
+ "%<%.*s%> directive output between %wu and "
+ "%wu bytes causes result to exceed %<INT_MAX%>",
+ dirlen,
+ target_to_host (hostdir, sizeof hostdir, dir.beg),
+ fmtres.range.min, fmtres.range.max);
+ }
+ else if ((!info.retval_used () || !info.bounded)
+ && (info.is_string_func ()))
+ /* Warn for calls to string functions that either aren't bounded
+ (sprintf) or whose return value isn't used. */
warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- fmtres.range.min > target_int_max ()
- ? G_("%<%.*s%> directive output between %wu and "
- "%wu bytes causes result to exceed "
- "%<INT_MAX%>")
- : G_("%<%.*s%> directive output between %wu and "
- "%wu bytes may cause result to exceed "
- "%<INT_MAX%>"), dirlen,
+ "%<%.*s%> directive output between %wu and "
+ "%wu bytes may cause result to exceed "
+ "%<INT_MAX%>", dirlen,
target_to_host (hostdir, sizeof hostdir, dir.beg),
fmtres.range.min, fmtres.range.max);
}
res->warned |= warned;
- if (!dir.beg[0] && res->warned && info.objsize < HOST_WIDE_INT_MAX)
+ if (!dir.beg[0] && res->warned)
{
- /* If a warning has been issued for buffer overflow or truncation
- (but not otherwise) help the user figure out how big a buffer
- they need. */
-
location_t callloc = gimple_location (info.callstmt);
unsigned HOST_WIDE_INT min = res->range.min;
unsigned HOST_WIDE_INT max = res->range.max;
- if (min == max)
- inform (callloc,
- (min == 1
- ? G_("%qE output %wu byte into a destination of size %wu")
- : G_("%qE output %wu bytes into a destination of size %wu")),
- info.func, min, info.objsize);
- else if (max < HOST_WIDE_INT_MAX)
- inform (callloc,
- "%qE output between %wu and %wu bytes into "
- "a destination of size %wu",
- info.func, min, max, info.objsize);
- else if (min < res->range.likely && res->range.likely < max)
- inform (callloc,
- "%qE output %wu or more bytes (assuming %wu) into "
- "a destination of size %wu",
- info.func, min, res->range.likely, info.objsize);
- else
- inform (callloc,
- "%qE output %wu or more bytes into a destination of size %wu",
- info.func, min, info.objsize);
+ if (info.objsize < HOST_WIDE_INT_MAX)
+ {
+ /* If a warning has been issued for buffer overflow or truncation
+ help the user figure out how big a buffer they need. */
+
+ if (min == max)
+ inform (callloc,
+ (min == 1
+ ? G_("%qE output %wu byte into a destination of size %wu")
+ : G_("%qE output %wu bytes into a destination of size "
+ "%wu")),
+ info.func, min, info.objsize);
+ else if (max < HOST_WIDE_INT_MAX)
+ inform (callloc,
+ "%qE output between %wu and %wu bytes into "
+ "a destination of size %wu",
+ info.func, min, max, info.objsize);
+ else if (min < res->range.likely && res->range.likely < max)
+ inform (callloc,
+ "%qE output %wu or more bytes (assuming %wu) into "
+ "a destination of size %wu",
+ info.func, min, res->range.likely, info.objsize);
+ else
+ inform (callloc,
+ "%qE output %wu or more bytes into a destination of size "
+ "%wu",
+ info.func, min, info.objsize);
+ }
+ else if (!info.is_string_func ())
+ {
+ /* If the warning is for a file function function like fprintf
+ of printf with no destination size just print the computed
+ result. */
+ if (min == max)
+ inform (callloc,
+ (min == 1
+ ? G_("%qE output %wu byte")
+ : G_("%qE output %wu bytes")),
+ info.func, min);
+ else if (max < HOST_WIDE_INT_MAX)
+ inform (callloc,
+ "%qE output between %wu and %wu bytes",
+ info.func, min, max);
+ else if (min < res->range.likely && res->range.likely < max)
+ inform (callloc,
+ "%qE output %wu or more bytes (assuming %wu)",
+ info.func, min, res->range.likely);
+ else
+ inform (callloc,
+ "%qE output %wu or more bytes",
+ info.func, min);
+ }
}
if (dump_file && *dir.beg)
}
/* Return the size of the object referenced by the expression DEST if
- available, or -1 otherwise. */
+ available, or the maximum possible size otherwise. */
static unsigned HOST_WIDE_INT
get_destination_size (tree dest)
{
- /* When there is no destination return -1. */
+ /* When there is no destination return the maximum. */
if (!dest)
- return HOST_WIDE_INT_M1U;
+ return HOST_WIDE_INT_MAX;
/* Initialize object size info before trying to compute it. */
init_object_sizes ();
if (compute_builtin_object_size (dest, ost, &size))
return size;
- return HOST_WIDE_INT_M1U;
+ return HOST_WIDE_INT_MAX;
}
/* Return true if the call described by INFO with result RES safe to
case BUILT_IN_PRINTF_CHK:
// Signature:
- // __builtin_printf_chk (it, format, ...)
+ // __builtin_printf_chk (ost, format, ...)
idx_format = 1;
info.argidx = 2;
idx_dstptr = -1;
--- /dev/null
+/* PR middle-end/88993 - GCC 9 -Wformat-overflow=2 should reflect real
+ libc limits
+ Verify that -Wformat-overflow=2 "may exceed" warnings are not issued
+ for printf family of functions.
+ { dg-do compile }
+ { dg-options "-O -Wformat -Wformat-overflow=2 -ftrack-macro-expansion=0" }
+ { dg-require-effective-target int32plus } */
+
+#define INT_MAX __INT_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+#if !__cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+#endif
+
+typedef struct FILE FILE;
+
+FILE *fp;
+
+#define T(...) __builtin_fprintf (__VA_ARGS__)
+
+/* Exercise the "%c" directive with constant arguments. */
+
+void test_fprintf_c_const (int width)
+{
+ /* Verify that a warning is only issued when the output is definitely
+ exceeded but not when exceeding it is possible but not inevitable.
+ Also verify that a note is printed with amount of output produced
+ by the call (the result - 1). */
+ T (fp, "%2147483647c", '1');
+ T (fp, "X%2147483647c", '2'); /* { dg-warning ".%2147483647c. directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ /* { dg-message ".__builtin_fprintf. output 2147483649 bytes" "note" { target *-*-* } .-1 } */
+ T (fp, "%2147483647cY", '3'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "%2147483648c", '1'); /* { dg-warning ".%2147483648c. directive output of 2147483648 bytes exceeds .INT_MAX." } */
+ T (fp, "X%2147483649c", '2'); /* { dg-warning ".%2147483649c. directive output of 2147483649 bytes exceeds .INT_MAX." } */
+ T (fp, "%2147483650cY", '3'); /* { dg-warning ".%2147483650c. directive output of 2147483650 bytes exceeds .INT_MAX." } */
+
+ T (fp, "%*c", INT_MAX, '1');
+ T (fp, "X%*c", INT_MAX, '1'); /* { dg-warning ".%*c. directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%*cY", INT_MAX, '1'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "X%*c", INT_MAX - 1, '1');
+ T (fp, "%*cY", INT_MAX - 1, '1');
+
+ T (fp, "%*cY", INT_MAX, '1'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T (fp, "X%*c", INT_MAX, '1'); /* { dg-warning ".%*c. directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+}
+
+/* Exercise the "%c" directive with arguments in a known range. */
+
+void test_fprintf_c_range (int width)
+{
+ /* Verify that an known upper bound doesn't trigger a warning. */
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*c", width, '1');
+ T (fp, "X%*c", width, '1');
+ T (fp, "%*cY", width, '1');
+
+ T (fp, "%*c", width, '1');
+ T (fp, "X%*c", width, '1');
+ T (fp, "%*cY", width, '1');
+
+ T (fp, "%*c%*c", width, '1', width, '2');
+ T (fp, "X%*cY%*cZ", width, '1', width, '2');
+
+ /* Verify that a lower bound in excess of 4095 doesn't trigger
+ a warning. */
+ if (width < 4096)
+ width = 4096;
+
+ T (fp, "%*c", width, '1');
+ T (fp, "X%*c", width, '1');
+ T (fp, "%*cY", width, '1');
+
+ /* Verify that a large lower bound triggers a warning when the total
+ result of the function definitely exceeds INT_MAX. */
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*c", width, '1');
+ T (fp, "X%*c", width, '2');
+ T (fp, "%*cY", width, '3');
+ T (fp, "X%*cY", width, '4'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ /* { dg-message ".__builtin_fprintf. output 2147483649 bytes" "note" { target *-*-* } .-1 } */
+}
+
+
+/* Exercise the "%s" directive. */
+
+void test_fprintf_s_const (int width, const char *s)
+{
+ T (fp, "%2147483647s", s);
+ T (fp, "%2147483647s", "1");
+
+ T (fp, "%2147483647.2147483647s", s);
+ T (fp, "%2147483647.2147483647s", "12");
+
+ T (fp, "X%2147483647s", s); /* { dg-warning ".%2147483647s. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%2147483647sY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "X%2147483647.1s", s); /* { dg-warning ".%2147483647\\\.1s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%2147483647.2sY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "X%1.2147483647s", s);
+ T (fp, "%2.2147483647sY", s);
+
+ T (fp, "X%1.2147483647s", "123");
+ T (fp, "%2.2147483647sY", "1234");
+
+ T (fp, "%2147483648s", s); /* { dg-warning "%2147483648s. directive output between 2147483648 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T (fp, "X%2147483649s", s); /* { dg-warning "%2147483649s. directive output between 2147483649 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T (fp, "%2147483650sY", s); /* { dg-warning ".%2147483650s. directive output between 2147483650 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+
+ T (fp, "%*s", INT_MAX, s);
+ T (fp, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "X%*s", INT_MAX - 1, s);
+ T (fp, "%*sY", INT_MAX - 1, s);
+
+ T (fp, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T (fp, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+
+ T (fp, "%*s%*s", width, s, width, s);
+ T (fp, "X%*sY%*sZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+ T (fp, "X%*sY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
+
+/* Exercise the "%ls" directive. */
+
+void test_fprintf_ls_const (int width, const wchar_t *s)
+{
+ T (fp, "%2147483647ls", s);
+ T (fp, "X%2147483647ls", s); /* { dg-warning ".%2147483647ls. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%2147483647lsY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "%2147483648ls", s); /* { dg-warning "%2147483648ls. directive output between 2147483648 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T (fp, "X%2147483649ls", s); /* { dg-warning "%2147483649ls. directive output between 2147483649 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T (fp, "%2147483650lsY", s); /* { dg-warning ".%2147483650ls. directive output between 2147483650 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+
+ T (fp, "%*ls", INT_MAX, s);
+ T (fp, "X%*ls", INT_MAX, s); /* { dg-warning ".%\\\*ls. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%*lsY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "X%*ls", INT_MAX - 1, s);
+ T (fp, "%*lsY", INT_MAX - 1, s);
+
+ T (fp, "%*lsY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T (fp, "X%*ls", INT_MAX, s); /* { dg-warning ".%\\\*ls. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*ls", width, s);
+ T (fp, "X%*ls", width, s);
+ T (fp, "%*lsY", width, s);
+
+ T (fp, "%*ls", width, s);
+ T (fp, "X%*ls", width, s);
+ T (fp, "%*lsY", width, s);
+
+ T (fp, "%*ls%*ls", width, s, width, s);
+ T (fp, "X%*lsY%*lsZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T (fp, "%*ls", width, s);
+ T (fp, "X%*ls", width, s);
+ T (fp, "%*lsY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*ls", width, s);
+ T (fp, "X%*ls", width, s);
+ T (fp, "%*lsY", width, s);
+ T (fp, "X%*lsY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
+
+
+/* Also exercise fprintf_chk. */
+
+#undef T
+#define T(...) __builtin___fprintf_chk (__VA_ARGS__)
+
+void test_fprintf_chk_s_const (int width)
+{
+ const char *s = "0123456789";
+
+ T (fp, 0, "%2147483647s", s);
+ T (fp, 0, "X%2147483647s", s); /* { dg-warning ".%2147483647s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T (fp, 0, "%2147483647sY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, 0, "%2147483648s", s); /* { dg-warning "%2147483648s. directive output of 2147483648 bytes exceeds .INT_MAX." } */
+ T (fp, 0, "X%2147483649s", s); /* { dg-warning "%2147483649s. directive output of 2147483649 bytes exceeds .INT_MAX." } */
+ T (fp, 0, "%2147483650sY", s); /* { dg-warning ".%2147483650s. directive output of 2147483650 bytes exceeds .INT_MAX." } */
+
+ T (fp, 0, "%*s", INT_MAX, s);
+ T (fp, 0, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T (fp, 0, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, 0, "X%*s", INT_MAX - 1, s);
+ T (fp, 0, "%*sY", INT_MAX - 1, s);
+
+ T (fp, 0, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T (fp, 0, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, 0, "%*s", width, s);
+ T (fp, 0, "X%*s", width, s);
+ T (fp, 0, "%*sY", width, s);
+
+ T (fp, 0, "%*s", width, s);
+ T (fp, 0, "X%*s", width, s);
+ T (fp, 0, "%*sY", width, s);
+
+ T (fp, 0, "%*s%*s", width, s, width, s);
+ T (fp, 0, "X%*sY%*sZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T (fp, 0, "%*s", width, s);
+ T (fp, 0, "X%*s", width, s);
+ T (fp, 0, "%*sY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, 0, "%*s", width, s);
+ T (fp, 0, "X%*s", width, s);
+ T (fp, 0, "%*sY", width, s);
+ T (fp, 0, "X%*sY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
+
+
+/* And finally exercise fprintf_unlocked. */
+
+#undef T
+#define T(...) __builtin_fprintf_unlocked (__VA_ARGS__)
+
+void test_fprintf_unlocked_s_const (int width)
+{
+ const char *s = "0123456789";
+
+ T (fp, "%2147483647s", s);
+ T (fp, "X%2147483647s", s); /* { dg-warning ".%2147483647s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%2147483647sY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "%2147483648s", s); /* { dg-warning "%2147483648s. directive output of 2147483648 bytes exceeds .INT_MAX." } */
+ T (fp, "X%2147483649s", s); /* { dg-warning "%2147483649s. directive output of 2147483649 bytes exceeds .INT_MAX." } */
+ T (fp, "%2147483650sY", s); /* { dg-warning ".%2147483650s. directive output of 2147483650 bytes exceeds .INT_MAX." } */
+
+ T (fp, "%*s", INT_MAX, s);
+ T (fp, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T (fp, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (fp, "X%*s", INT_MAX - 1, s);
+ T (fp, "%*sY", INT_MAX - 1, s);
+
+ T (fp, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T (fp, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+
+ T (fp, "%*s%*s", width, s, width, s);
+ T (fp, "X%*sY%*sZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (fp, "%*s", width, s);
+ T (fp, "X%*s", width, s);
+ T (fp, "%*sY", width, s);
+ T (fp, "X%*sY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
--- /dev/null
+/* PR middle-end/88993 - GCC 9 -Wformat-overflow=2 should reflect real
+ libc limits
+ Verify that -Wformat-overflow=2 "may exceed" warnings are not issued
+ for printf family of functions.
+ { dg-do compile }
+ { dg-options "-O -Wformat -Wformat-overflow=2 -ftrack-macro-expansion=0" }
+ { dg-require-effective-target int32plus } */
+
+
+#define INT_MAX __INT_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+#if !__cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+#endif
+
+#define T(...) __builtin_printf (__VA_ARGS__)
+
+/* Exercise the "%c" directive with constant arguments. */
+
+void test_printf_c_const (int width)
+{
+ /* Verify that a warning is only issued when the output is definitely
+ exceeded but not when exceeding it is possible but not inevitable. */
+ T ("%2147483647c", '1');
+ T ("X%2147483647c", '2'); /* { dg-warning ".%*c. directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T ("%2147483647cY", '3'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("%2147483648c", '1'); /* { dg-warning ".%2147483648c. directive output of 2147483648 bytes exceeds .INT_MAX." } */
+ T ("X%2147483649c", '2'); /* { dg-warning ".%2147483649c. directive output of 2147483649 bytes exceeds .INT_MAX." } */
+ T ("%2147483650cY", '3'); /* { dg-warning ".%2147483650c. directive output of 2147483650 bytes exceeds .INT_MAX." } */
+
+ T ("%*c", INT_MAX, '1');
+ T ("X%*c", INT_MAX, '1'); /* { dg-warning ".%*c. directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T ("%*cY", INT_MAX, '1'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("X%*c", INT_MAX - 1, '1');
+ T ("%*cY", INT_MAX - 1, '1');
+
+ T ("%*cY", INT_MAX, '1'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T ("X%*c", INT_MAX, '1'); /* { dg-warning ".%*c. directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*c", width, '1');
+ T ("X%*c", width, '1');
+ T ("%*cY", width, '1');
+
+ T ("%*c", width, '1');
+ T ("X%*c", width, '1');
+ T ("%*cY", width, '1');
+
+ T ("%*c%*c", width, '1', width, '2');
+ T ("X%*cY%*cZ", width, '1', width, '2');
+
+ if (width < 4096)
+ width = 4096;
+
+ T ("%*c", width, '1');
+ T ("X%*c", width, '1');
+ T ("%*cY", width, '1');
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*c", width, '1');
+ T ("X%*c", width, '2');
+ T ("%*cY", width, '3');
+ T ("X%*cY", width, '4'); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
+
+
+/* Exercise the "%s" directive with constant arguments. */
+
+void test_printf_s_const (int width, const char *s)
+{
+ T ("%2147483647s", s);
+ T ("X%2147483647s", s); /* { dg-warning ".%2147483647s. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T ("%2147483647sY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("%2147483648s", s); /* { dg-warning "%2147483648s. directive output between 2147483648 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T ("X%2147483649s", s); /* { dg-warning "%2147483649s. directive output between 2147483649 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T ("%2147483650sY", s); /* { dg-warning ".%2147483650s. directive output between 2147483650 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+
+ T ("%*s", INT_MAX, s);
+ T ("X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T ("%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("X%*s", INT_MAX - 1, s);
+ T ("%*sY", INT_MAX - 1, s);
+
+ T ("%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T ("X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+
+ T ("%*s%*s", width, s, width, s);
+ T ("X%*sY%*sZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+ T ("X%*sY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
+
+/* Exercise the "%ls" directive with constant arguments. */
+
+void test_printf_ls_const (int width, const wchar_t *s)
+{
+ T ("%2147483647ls", s);
+ T ("X%2147483647ls", s); /* { dg-warning ".%2147483647ls. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T ("%2147483647lsY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("%2147483648ls", s); /* { dg-warning "%2147483648ls. directive output between 2147483648 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T ("X%2147483649ls", s); /* { dg-warning "%2147483649ls. directive output between 2147483649 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+ T ("%2147483650lsY", s); /* { dg-warning ".%2147483650ls. directive output between 2147483650 and \[0-9\]+ bytes exceeds .INT_MAX." } */
+
+ T ("%*ls", INT_MAX, s);
+ T ("X%*ls", INT_MAX, s); /* { dg-warning ".%\\\*ls. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+ T ("%*lsY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("X%*ls", INT_MAX - 1, s);
+ T ("%*lsY", INT_MAX - 1, s);
+
+ T ("%*lsY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T ("X%*ls", INT_MAX, s); /* { dg-warning ".%\\\*ls. directive output between 2147483647 and \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*ls", width, s);
+ T ("X%*ls", width, s);
+ T ("%*lsY", width, s);
+
+ T ("%*ls", width, s);
+ T ("X%*ls", width, s);
+ T ("%*lsY", width, s);
+
+ T ("%*ls%*ls", width, s, width, s);
+ T ("X%*lsY%*lsZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T ("%*ls", width, s);
+ T ("X%*ls", width, s);
+ T ("%*lsY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*ls", width, s);
+ T ("X%*ls", width, s);
+ T ("%*lsY", width, s);
+ T ("X%*lsY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
+
+
+/* Also exercise printf_chk. */
+
+#undef T
+#define T(...) __builtin___printf_chk (__VA_ARGS__)
+
+void test_printf_chk_s_const (int width)
+{
+ const char *s = "0123456789";
+
+ T (0, "%2147483647s", s);
+ T (0, "X%2147483647s", s); /* { dg-warning ".%2147483647s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T (0, "%2147483647sY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (0, "%2147483648s", s); /* { dg-warning "%2147483648s. directive output of 2147483648 bytes exceeds .INT_MAX." } */
+ T (0, "X%2147483649s", s); /* { dg-warning "%2147483649s. directive output of 2147483649 bytes exceeds .INT_MAX." } */
+ T (0, "%2147483650sY", s); /* { dg-warning ".%2147483650s. directive output of 2147483650 bytes exceeds .INT_MAX." } */
+
+ T (0, "%*s", INT_MAX, s);
+ T (0, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T (0, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T (0, "X%*s", INT_MAX - 1, s);
+ T (0, "%*sY", INT_MAX - 1, s);
+
+ T (0, "%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T (0, "X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (0, "%*s", width, s);
+ T (0, "X%*s", width, s);
+ T (0, "%*sY", width, s);
+
+ T (0, "%*s", width, s);
+ T (0, "X%*s", width, s);
+ T (0, "%*sY", width, s);
+
+ T (0, "%*s%*s", width, s, width, s);
+ T (0, "X%*sY%*sZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T (0, "%*s", width, s);
+ T (0, "X%*s", width, s);
+ T (0, "%*sY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T (0, "%*s", width, s);
+ T (0, "X%*s", width, s);
+ T (0, "%*sY", width, s);
+ T (0, "X%*sY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
+
+
+/* And finally exercise printf_unlocked. */
+
+#undef T
+#define T(...) __builtin_printf_unlocked (__VA_ARGS__)
+
+void test_printf_unlocked_s_const (int width)
+{
+ const char *s = "0123456789";
+
+ T ("%2147483647s", s);
+ T ("X%2147483647s", s); /* { dg-warning ".%2147483647s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T ("%2147483647sY", s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("%2147483648s", s); /* { dg-warning "%2147483648s. directive output of 2147483648 bytes exceeds .INT_MAX." } */
+ T ("X%2147483649s", s); /* { dg-warning "%2147483649s. directive output of 2147483649 bytes exceeds .INT_MAX." } */
+ T ("%2147483650sY", s); /* { dg-warning ".%2147483650s. directive output of 2147483650 bytes exceeds .INT_MAX." } */
+
+ T ("%*s", INT_MAX, s);
+ T ("X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+ T ("%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+
+ T ("X%*s", INT_MAX - 1, s);
+ T ("%*sY", INT_MAX - 1, s);
+
+ T ("%*sY", INT_MAX, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+ T ("X%*s", INT_MAX, s); /* { dg-warning ".%\\\*s. directive output of 2147483647 bytes causes result to exceed .INT_MAX." } */
+
+ if (width > INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+
+ T ("%*s%*s", width, s, width, s);
+ T ("X%*sY%*sZ", width, s, width, s);
+
+ if (width < 4096)
+ width = 4096;
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+
+ if (width < INT_MAX - 1)
+ width = INT_MAX - 1;
+
+ T ("%*s", width, s);
+ T ("X%*s", width, s);
+ T ("%*sY", width, s);
+ T ("X%*sY", width, s); /* { dg-warning ".Y. directive output of 1 bytes causes result to exceed .INT_MAX." } */
+}
/* PR middle-end/79448 - unhelpful -Wformat-truncation=2 warning
{ dg-do compile }
- { dg-options "-O2 -Wformat -Wformat-truncation=2 -ftrack-macro-expansion=0" }
+ { dg-options "-O2 -Wformat -Wformat-truncation=2 -ftrack-macro-expansion=0" }
{ dg-require-effective-target ptr32plus } */
typedef __SIZE_TYPE__ size_t;
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. */
+ does not trigger a warning. (No known implementation has trouble
+ with this). */
+ T (-1, "%s", ar->a4kp1);
+
+ /* Verify that a %s directive with width greater than 4095 does
+ trigger a warning even if the string argument is not longer
+ than 4k. Glibc only has trouble with directives whose width
+ or precision exceeds 64K or so:
+ https://bugzilla.redhat.com/show_bug.cgi?id=441945 *
+ but hardcoding that as the limit and assuming no other
+ implementation has a lower one seems unwise. */
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
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" } */
+ /* Similar to the above, verify there's no warning for an array
+ just because its size is INT_MAX bytes. */
+ T (-1, "%s", ar->amax);
}
/* The range here happens to be a property of the compiler, not
one of the target. */
T ("%9223372036854775808i", 0); /* { dg-warning "width out of range" "first" } */
- /* { dg-warning "result to exceed .INT_MAX." "second" { target *-*-* } .-1 } */
+ /* { dg-warning "exceeds .INT_MAX." "second" { target *-*-* } .-1 } */
T ("%.9223372036854775808i", 0); /* { dg-warning "precision out of range" "first" } */
- /* { dg-warning "causes result to exceed .INT_MAX." "second" { target *-*-* } .-1 } */
+ /* { dg-warning "exceeds .INT_MAX." "second" { target *-*-* } .-1 } */
/* The following is diagnosed by -Wformat (disabled here). */
/* T ("%9223372036854775808$i", 0); */