public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
@ 2019-02-05  3:58 Martin Sebor
  2019-02-05  5:06 ` Eric Gallager
  2019-02-11 18:24 ` Martin Sebor
  0 siblings, 2 replies; 9+ messages in thread
From: Martin Sebor @ 2019-02-05  3:58 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1272 bytes --]

The attached patch relaxes -Wformat-overflow=2 to avoid warning about
individual directives that might (but need not) exceed the 4095 byte
limit, and about the total function output that likewise might (but
need not) exceed the INT_MAX limit.

The bug report actually requests that instead of the standard minimum
of 4095 bytes, GCC consider real libc limits, but trying to figure
out what these real limits might be (they're not documented anywhere,
AFAIK) and hardcoding them into GCC doesn't seem like a good solution.

Instead, the patch only does little more than the bare minimum to
suppress these pedantic warnings, and it only does that for the "may
exceed" cases and not for those where the size of output definitely
exceeds either limit.  Using the formatted functions to write such
large amounts of data seems more likely to be a bug than intentional,
and at level 2 issuing the warning seems appropriate unless the return
value of the function is tested.  When it is, even tough exceeding
these limits is strictly undefined, it seems reasonable to assume that
a quality libc implementation will detect it and return an error (as
required by POSIX).

So with the patch, the only way to get this warning is for calls to
sprintf or to unchecked snprintf.

Martin

[-- Attachment #2: gcc-88993.diff --]
[-- Type: text/x-patch, Size: 19561 bytes --]

PR c/88993 - GCC 9 -Wformat-overflow=2 should reflect real libc limits

gcc/ChangeLog:

	PR c/88993
	* 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 c/88993
	* gcc.dg/tree-ssa/builtin-fprintf-warn-2.c: New test.
	* gcc.dg/tree-ssa/builtin-printf-warn-2.c: New test.
	* testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c: Adjust.

Index: gimple-ssa-sprintf.c
===================================================================
--- gimple-ssa-sprintf.c	(revision 268525)
+++ gimple-ssa-sprintf.c	(working copy)
@@ -943,6 +943,29 @@ struct sprintf_dom_walker::call_info
   {
     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 fncodetions.  */
+  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').  */
@@ -2847,7 +2870,9 @@ format_directive (const sprintf_dom_walker::call_i
 	 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 (),
@@ -2855,17 +2880,21 @@ format_directive (const sprintf_dom_walker::call_i
 			  "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 (),
-			  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 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 (),
+			  "%<%.*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);
     }
 
   /* Has the likely and maximum directive output exceeded INT_MAX?  */
@@ -2885,26 +2914,32 @@ format_directive (const sprintf_dom_walker::call_i
 	      && maxximax
 	      && fmtres.range.max < HOST_WIDE_INT_MAX)))
     {
-      /* The directive output causes the total length of output
-	 to exceed INT_MAX bytes.  */
+      /* The directive output or either causes or may cause the total
+	 length of output to exceed INT_MAX bytes.  */
 
-      if (fmtres.range.min == fmtres.range.max)
+      if (likelyximax && 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
+      else if (fmtres.range.min > target_int_max ())
 	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 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 (),
+			  "%<%.*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);
     }
 
   if (!warned && fmtres.nonstr)
@@ -3842,7 +3877,7 @@ sprintf_dom_walker::handle_gimple_call (gimple_stm
 
     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;
Index: testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c	(nonexistent)
+++ testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c	(working copy)
@@ -0,0 +1,159 @@
+/* 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_printf_c_const (int width)
+{
+  /* Verify that a "may exceed" warning is only issued when the output
+     is definitely exceeded but not when exceeding it is possible but
+     not inevitable.  */
+  T (fp, "%*c", INT_MAX, '1');    /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T (fp, "%*c", 4096, '1');       /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T (fp, "X%*c", 4095, '1');
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T (fp, "%*c", width, '1');
+  T (fp, "%*cX", width, '1');
+  T (fp, "%*c%*c", width, '1', width, '2');
+  T (fp, "X%*cY%*cZ", width, '1', width, '2');
+
+  if (width < 4096)
+    width = 4096;
+
+  T (fp, "%*c", width, '1');      /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+
+/* Exercise the "%s" directive with constant arguments.  */
+
+void test_printf_s_const (int width)
+{
+  const char *s = "";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T (fp, "%*s", INT_MAX, s);      /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T (fp, "%*s", 4096, s);         /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T (fp, "X%*s", 4095, s);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T (fp, "%*s", width, s);
+  T (fp, "%*sX", 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);        /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+/* Exercise the "%ls" directive with constant arguments.  */
+
+void test_printf_ls_const (int width)
+{
+  const wchar_t *ls = L"";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T (fp, "%*ls",  INT_MAX, ls);   /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T (fp, "%*ls", 4096, ls);       /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T (fp, "X%*ls", 4095, ls);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T (fp, "%*ls", width, ls);
+  T (fp, "%*lsX", width, ls);
+  T (fp, "%*ls%*ls", width, ls, width, ls);
+  T (fp, "X%*lsY%*lsZ", width, ls, width, ls);
+
+  if (width < 4096)
+    width = 4096;
+
+  T (fp, "%*ls", width, ls);      /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+
+/* Also exercise fprintf_chk.  */
+
+#undef T
+#define T(...) __builtin___fprintf_chk (__VA_ARGS__)
+
+void test_printf_chk_s_const (int width)
+{
+  const char *s = "0123456789";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T (fp, 0, "%*s", INT_MAX, s);   /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T (fp, 0, "%*s", 4096, s);      /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T (fp, 0, "X%*s", 4095, s);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T (fp, 0, "%*s", width, s);
+  T (fp, 0, "%*sX", 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);     /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+
+/* And finally exercise fprintf_unlocked.  */
+
+#undef T
+#define T(...) __builtin_fprintf_unlocked (__VA_ARGS__)
+
+void test_printf_unlocked_s_const (int width)
+{
+  const char *s = "0123456789";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T (fp, "%*s",  INT_MAX, s);     /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T (fp, "%*s",  4096, s);        /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T (fp, "X%*s", 4095, s);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T (fp, "%*s", width, s);
+  T (fp, "%*sX", 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);        /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
Index: testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c	(nonexistent)
+++ testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c	(working copy)
@@ -0,0 +1,170 @@
+/* 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 } */
+
+/* When debugging, define LINE to the line number of the test case to exercise
+   and avoid exercising any of the others.  */
+#ifndef LINE
+# define LINE 0
+#endif
+
+#define INT_MAX __INT_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+#if !__cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+#endif
+
+int dummy_printf (const char*, ...);
+
+
+/* Helper to expand function to either __builtin_f or dummy_f to
+   make debugging GCC easy.  */
+#define T(...)							\
+  (((!LINE || LINE == __LINE__)					\
+    ? __builtin_printf : dummy_printf) (__VA_ARGS__))
+
+/* Exercise the "%c" directive with constant arguments.  */
+
+void test_printf_c_const (int width)
+{
+  /* Verify that a "may exceed" warning is only issued when the output
+     is definitely exceeded but not when exceeding it is possible but
+     not inevitable.  */
+  T ("%*c",  INT_MAX, '1');       /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T ("%*c",  4096, '1');          /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T ("X%*c", 4095, '1');
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T ("%*c", width, '1');
+  T ("%*cX", 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');         /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+
+/* Exercise the "%s" directive with constant arguments.  */
+
+void test_printf_s_const (int width)
+{
+  const char *s = "";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T ("%*s",  INT_MAX, s);         /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T ("%*s",  4096, s);            /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T ("X%*s", 4095, s);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T ("%*s", width, s);
+  T ("%*sX", 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);            /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+/* Exercise the "%ls" directive with constant arguments.  */
+
+void test_printf_ls_const (int width)
+{
+  const wchar_t *ls = L"";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T ("%*ls",  INT_MAX, ls);       /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T ("%*ls",  4096, ls);          /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T ("X%*ls", 4095, ls);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T ("%*ls", width, ls);
+  T ("%*lsX", width, ls);
+  T ("%*ls%*ls", width, ls, width, ls);
+  T ("X%*lsY%*lsZ", width, ls, width, ls);
+
+  if (width < 4096)
+    width = 4096;
+
+  T ("%*ls", width, ls);          /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+
+/* 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";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T (0, "%*s", INT_MAX, s);       /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T (0, "%*s", 4096, s);          /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T (0, "X%*s", 4095, s);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T (0, "%*s", width, s);
+  T (0, "%*sX", 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);         /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
+
+
+/* And finally exercise printf_unlocked.  */
+
+#undef T
+#define T(...)							\
+  (((!LINE || LINE == __LINE__)					\
+    ? __builtin_printf_unlocked : dummy_printf) (__VA_ARGS__))
+
+void test_printf_unlocked_s_const (int width)
+{
+  const char *s = "0123456789";
+
+  /* Verify that output in excess of INT_MAX bytes is diagnosed even
+     when the size of the destination object is unknown.  */
+  T ("%*s",  INT_MAX, s);         /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+  T ("%*s",  4096, s);            /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */
+  T ("X%*s", 4095, s);
+
+  if (width > INT_MAX - 1)
+    width = INT_MAX - 1;
+
+  T ("%*s", width, s);
+  T ("%*sX", 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);            /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */
+}
Index: testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c	(revision 268525)
+++ testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c	(working copy)
@@ -166,11 +166,17 @@ void test_string_checked (const char *s, const str
   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" } */
+     does not trigger a warning.  (No known implementation has trouble
+     with this).  */
+  T (-1, "%s", ar->a4kp1);
 
-  /* Also verify that a %s directive with width greater than 4095
-     triggers a warning even if the argument is not longer than 4k.  */
+  /* 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
@@ -190,5 +196,7 @@ void test_string_checked (const char *s, const str
   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);
 }

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-05  3:58 [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993) Martin Sebor
@ 2019-02-05  5:06 ` Eric Gallager
  2019-02-11 18:24 ` Martin Sebor
  1 sibling, 0 replies; 9+ messages in thread
From: Eric Gallager @ 2019-02-05  5:06 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches

On 2/4/19, Martin Sebor <msebor@gmail.com> wrote:
> The attached patch relaxes -Wformat-overflow=2 to avoid warning about
> individual directives that might (but need not) exceed the 4095 byte
> limit, and about the total function output that likewise might (but
> need not) exceed the INT_MAX limit.
>
> The bug report actually requests that instead of the standard minimum
> of 4095 bytes, GCC consider real libc limits, but trying to figure
> out what these real limits might be (they're not documented anywhere,
> AFAIK) and hardcoding them into GCC doesn't seem like a good solution.
>
> Instead, the patch only does little more than the bare minimum to
> suppress these pedantic warnings, and it only does that for the "may
> exceed" cases and not for those where the size of output definitely
> exceeds either limit.  Using the formatted functions to write such
> large amounts of data seems more likely to be a bug than intentional,
> and at level 2 issuing the warning seems appropriate unless the return
> value of the function is tested.  When it is, even tough exceeding
> these limits is strictly undefined, it seems reasonable to assume that
> a quality libc implementation will detect it and return an error (as
> required by POSIX).

Reminder that gcc is available for non-POSIX platforms (e.g. mingw)

>
> So with the patch, the only way to get this warning is for calls to
> sprintf or to unchecked snprintf.
>
> Martin
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-05  3:58 [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993) Martin Sebor
  2019-02-05  5:06 ` Eric Gallager
@ 2019-02-11 18:24 ` Martin Sebor
  2019-02-20  0:44   ` PING " Martin Sebor
  1 sibling, 1 reply; 9+ messages in thread
From: Martin Sebor @ 2019-02-11 18:24 UTC (permalink / raw)
  To: gcc-patches

Ping: https://gcc.gnu.org/ml/gcc-patches/2019-02/msg00224.html

(This patch also handles bug 88835.)

On 2/4/19 8:58 PM, Martin Sebor wrote:
> The attached patch relaxes -Wformat-overflow=2 to avoid warning about
> individual directives that might (but need not) exceed the 4095 byte
> limit, and about the total function output that likewise might (but
> need not) exceed the INT_MAX limit.
> 
> The bug report actually requests that instead of the standard minimum
> of 4095 bytes, GCC consider real libc limits, but trying to figure
> out what these real limits might be (they're not documented anywhere,
> AFAIK) and hardcoding them into GCC doesn't seem like a good solution.
> 
> Instead, the patch only does little more than the bare minimum to
> suppress these pedantic warnings, and it only does that for the "may
> exceed" cases and not for those where the size of output definitely
> exceeds either limit.  Using the formatted functions to write such
> large amounts of data seems more likely to be a bug than intentional,
> and at level 2 issuing the warning seems appropriate unless the return
> value of the function is tested.  When it is, even tough exceeding
> these limits is strictly undefined, it seems reasonable to assume that
> a quality libc implementation will detect it and return an error (as
> required by POSIX).
> 
> So with the patch, the only way to get this warning is for calls to
> sprintf or to unchecked snprintf.
> 
> Martin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* PING [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-11 18:24 ` Martin Sebor
@ 2019-02-20  0:44   ` Martin Sebor
  2019-02-21 19:08     ` Jeff Law
  2019-02-22 23:17     ` Jakub Jelinek
  0 siblings, 2 replies; 9+ messages in thread
From: Martin Sebor @ 2019-02-20  0:44 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1896 bytes --]

I received feedback on the first patch that it doesn't suppress all
the instances of the warning so I've relaxed the checker even more
to avoid the excess instances seen in Elfutils and beefed up
the tests.  The top of trunk compiles cleanly now with just
the three instances of -Wformat-truncation=2 that are not
the subject of the two PRs.

Martin

On 2/11/19 11:24 AM, Martin Sebor wrote:
> Ping: https://gcc.gnu.org/ml/gcc-patches/2019-02/msg00224.html
> 
> (This patch also handles bug 88835.)
> 
> On 2/4/19 8:58 PM, Martin Sebor wrote:
>> The attached patch relaxes -Wformat-overflow=2 to avoid warning about
>> individual directives that might (but need not) exceed the 4095 byte
>> limit, and about the total function output that likewise might (but
>> need not) exceed the INT_MAX limit.
>>
>> The bug report actually requests that instead of the standard minimum
>> of 4095 bytes, GCC consider real libc limits, but trying to figure
>> out what these real limits might be (they're not documented anywhere,
>> AFAIK) and hardcoding them into GCC doesn't seem like a good solution.
>>
>> Instead, the patch only does little more than the bare minimum to
>> suppress these pedantic warnings, and it only does that for the "may
>> exceed" cases and not for those where the size of output definitely
>> exceeds either limit.  Using the formatted functions to write such
>> large amounts of data seems more likely to be a bug than intentional,
>> and at level 2 issuing the warning seems appropriate unless the return
>> value of the function is tested.  When it is, even tough exceeding
>> these limits is strictly undefined, it seems reasonable to assume that
>> a quality libc implementation will detect it and return an error (as
>> required by POSIX).
>>
>> So with the patch, the only way to get this warning is for calls to
>> sprintf or to unchecked snprintf.
>>
>> Martin
> 


[-- Attachment #2: gcc-88993.diff --]
[-- Type: text/x-patch, Size: 39876 bytes --]

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/88835
	* 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::compute_format_length): Return HWI_MAX rather than -1.
	(sprintf_dom_walker::handle_gimple_call): Fix a typo in a comment.

gcc/testsuite/ChangeLog:

	PR tree-optimization/88993
	PR tree-optimization/88835
	* 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.

Index: gcc/gimple-ssa-sprintf.c
===================================================================
--- gcc/gimple-ssa-sprintf.c	(revision 269022)
+++ gcc/gimple-ssa-sprintf.c	(working copy)
@@ -943,6 +943,29 @@ struct sprintf_dom_walker::call_info
   {
     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 fncodetions.  */
+  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').  */
@@ -2839,6 +2862,8 @@ format_directive (const sprintf_dom_walker::call_i
   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)))
     {
@@ -2847,7 +2872,9 @@ format_directive (const sprintf_dom_walker::call_i
 	 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 (),
@@ -2855,17 +2882,21 @@ format_directive (const sprintf_dom_walker::call_i
 			  "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 (),
-			  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 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 (),
+			  "%<%.*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);
     }
 
   /* Has the likely and maximum directive output exceeded INT_MAX?  */
@@ -2885,25 +2916,49 @@ format_directive (const sprintf_dom_walker::call_i
 	      && 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)
+      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 (),
-			  "%<%.*s%> directive output of %wu bytes causes "
-			  "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);
-      else
-	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,
-			  target_to_host (hostdir, sizeof hostdir, dir.beg),
 			  fmtres.range.min, fmtres.range.max);
     }
 
@@ -2942,37 +2997,65 @@ format_directive (const sprintf_dom_walker::call_i
 
   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)
@@ -3499,14 +3582,14 @@ sprintf_dom_walker::compute_format_length (call_in
 }
 
 /* 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 ();
@@ -3521,7 +3604,7 @@ get_destination_size (tree dest)
   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
@@ -3842,7 +3925,7 @@ sprintf_dom_walker::handle_gimple_call (gimple_stm
 
     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;
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c	(working copy)
@@ -0,0 +1,324 @@
+/* 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 2147483647 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." } */
+}
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c	(working copy)
@@ -0,0 +1,293 @@
+/* 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." } */
+}
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c	(revision 269022)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c	(working copy)
@@ -1,6 +1,6 @@
 /* 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;
@@ -166,11 +166,17 @@ void test_string_checked (const char *s, const str
   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" } */
+     does not trigger a warning.  (No known implementation has trouble
+     with this).  */
+  T (-1, "%s", ar->a4kp1);
 
-  /* Also verify that a %s directive with width greater than 4095
-     triggers a warning even if the argument is not longer than 4k.  */
+  /* 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
@@ -190,5 +196,7 @@ void test_string_checked (const char *s, const str
   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);
 }
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-18.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-18.c	(revision 269022)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-18.c	(working copy)
@@ -118,9 +118,9 @@ void test_width_and_precision_out_of_range (char *
   /* 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); */

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-20  0:44   ` PING " Martin Sebor
@ 2019-02-21 19:08     ` Jeff Law
  2019-02-22 23:17     ` Jakub Jelinek
  1 sibling, 0 replies; 9+ messages in thread
From: Jeff Law @ 2019-02-21 19:08 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches

On 2/19/19 5:43 PM, Martin Sebor wrote:
> I received feedback on the first patch that it doesn't suppress all
> the instances of the warning so I've relaxed the checker even more
> to avoid the excess instances seen in Elfutils and beefed up
> the tests.  The top of trunk compiles cleanly now with just
> the three instances of -Wformat-truncation=2 that are not
> the subject of the two PRs.
> 
> Martin
> 
> On 2/11/19 11:24 AM, Martin Sebor wrote:
>> Ping: https://gcc.gnu.org/ml/gcc-patches/2019-02/msg00224.html
>>
>> (This patch also handles bug 88835.)
>>
>> On 2/4/19 8:58 PM, Martin Sebor wrote:
>>> The attached patch relaxes -Wformat-overflow=2 to avoid warning about
>>> individual directives that might (but need not) exceed the 4095 byte
>>> limit, and about the total function output that likewise might (but
>>> need not) exceed the INT_MAX limit.
>>>
>>> The bug report actually requests that instead of the standard minimum
>>> of 4095 bytes, GCC consider real libc limits, but trying to figure
>>> out what these real limits might be (they're not documented anywhere,
>>> AFAIK) and hardcoding them into GCC doesn't seem like a good solution.
>>>
>>> Instead, the patch only does little more than the bare minimum to
>>> suppress these pedantic warnings, and it only does that for the "may
>>> exceed" cases and not for those where the size of output definitely
>>> exceeds either limit.  Using the formatted functions to write such
>>> large amounts of data seems more likely to be a bug than intentional,
>>> and at level 2 issuing the warning seems appropriate unless the return
>>> value of the function is tested.  When it is, even tough exceeding
>>> these limits is strictly undefined, it seems reasonable to assume that
>>> a quality libc implementation will detect it and return an error (as
>>> required by POSIX).
>>>
>>> So with the patch, the only way to get this warning is for calls to
>>> sprintf or to unchecked snprintf.
>>>
>>> Martin
>>
> 
> 
> gcc-88993.diff
> 
> 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/88835
> 	* 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::compute_format_length): Return HWI_MAX rather than -1.
> 	(sprintf_dom_walker::handle_gimple_call): Fix a typo in a comment.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR tree-optimization/88993
> 	PR tree-optimization/88835
> 	* 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.
> 
> Index: gcc/gimple-ssa-sprintf.c
> ===================================================================
> --- gcc/gimple-ssa-sprintf.c	(revision 269022)
> +++ gcc/gimple-ssa-sprintf.c	(working copy)
> @@ -943,6 +943,29 @@ struct sprintf_dom_walker::call_info
>    {
>      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 fncodetions.  */
I believe fncodetions should be functions :-)

OK with the  nit fixed.  And yes, I think it would be exceedingly
difficult to determine with any reliability what the system limits
really are.

jeff

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-20  0:44   ` PING " Martin Sebor
  2019-02-21 19:08     ` Jeff Law
@ 2019-02-22 23:17     ` Jakub Jelinek
  2019-02-22 23:33       ` Martin Sebor
  1 sibling, 1 reply; 9+ messages in thread
From: Jakub Jelinek @ 2019-02-22 23:17 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches

On Tue, Feb 19, 2019 at 05:43:53PM -0700, Martin Sebor wrote:
> 	PR tree-optimization/88993
> 	PR tree-optimization/88835
> 	* 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.

Can you please, when testing a patch like this where you should expect
tbe wordsize will play an important role to test it with
make check-gcc RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} tree-ssa.exp=builtin-*printf-warn*'
?
There are many failures on ilp32 targets.

+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 114)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 115)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 116)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 166)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 167)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 168)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 224)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 225)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 226)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 282)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 283)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 284)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 36)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 37)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 38)
+FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c (test for excess errors)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 135)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 136)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 137)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 193)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 194)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 195)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 251)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 252)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 253)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 30)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 31)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 32)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 83)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 84)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 85)
+FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c (test for excess errors)

and

FAIL: gcc.dg/tree-ssa/builtin-sprintf-10.c (test for excess errors)
FAIL: gcc.dg/tree-ssa/builtin-sprintf-warn-18.c second (test for warnings, line 120)
FAIL: gcc.dg/tree-ssa/builtin-sprintf-warn-18.c second (test for warnings, line 122)

are not new today.

	Jakub

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-22 23:17     ` Jakub Jelinek
@ 2019-02-22 23:33       ` Martin Sebor
  2019-02-23  0:27         ` Jakub Jelinek
  0 siblings, 1 reply; 9+ messages in thread
From: Martin Sebor @ 2019-02-22 23:33 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 2/22/19 3:44 PM, Jakub Jelinek wrote:
> On Tue, Feb 19, 2019 at 05:43:53PM -0700, Martin Sebor wrote:
>> 	PR tree-optimization/88993
>> 	PR tree-optimization/88835
>> 	* 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.
> 
> Can you please, when testing a patch like this where you should expect
> tbe wordsize will play an important role to test it with
> make check-gcc RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} tree-ssa.exp=builtin-*printf-warn*'
> ?
> There are many failures on ilp32 targets.
> 
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 114)

I don't see these failures with -m32.  They must be specific to 32-bit
GCC itself.

> +FAIL: gcc.dg/tree-ssa/l  (test for warnings, line 115)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 116)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 166)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 167)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 168)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 224)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 225)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 226)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 282)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 283)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 284)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 36)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 37)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 38)
> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c (test for excess errors)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 135)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 136)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 137)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 193)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 194)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 195)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 251)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 252)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 253)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 30)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 31)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 32)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 83)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 84)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c  (test for warnings, line 85)
> +FAIL: gcc.dg/tree-ssa/builtin-printf-warn-2.c (test for excess errors)
> 
> and
> 
> FAIL: gcc.dg/tree-ssa/builtin-sprintf-10.c (test for excess errors)
> FAIL: gcc.dg/tree-ssa/builtin-sprintf-warn-18.c second (test for warnings, line 120)
> FAIL: gcc.dg/tree-ssa/builtin-sprintf-warn-18.c second (test for warnings, line 122)
> 
> are not new today.

I silenced these warnings: they were due to bug 77970 where -Wformat
complains for

   printf ("%lc", L'x');

with -m32 but not with -m64.

Martin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-22 23:33       ` Martin Sebor
@ 2019-02-23  0:27         ` Jakub Jelinek
  2019-02-23  1:02           ` Martin Sebor
  0 siblings, 1 reply; 9+ messages in thread
From: Jakub Jelinek @ 2019-02-23  0:27 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches

On Fri, Feb 22, 2019 at 04:17:14PM -0700, Martin Sebor wrote:
> On 2/22/19 3:44 PM, Jakub Jelinek wrote:
> > On Tue, Feb 19, 2019 at 05:43:53PM -0700, Martin Sebor wrote:
> > > 	PR tree-optimization/88993
> > > 	PR tree-optimization/88835
> > > 	* 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.
> > 
> > Can you please, when testing a patch like this where you should expect
> > tbe wordsize will play an important role to test it with
> > make check-gcc RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} tree-ssa.exp=builtin-*printf-warn*'
> > ?
> > There are many failures on ilp32 targets.
> > 
> > +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 114)
> 
> I don't see these failures with -m32.  They must be specific to 32-bit
> GCC itself.

My bootstrap was indeed i686-linux, not x86_64-linux compiler with -m32.
E.g. target_strtol10 for some strange reason returns long rather than
HOST_WIDE_INT and checks LONG_MAX rather than HOST_WIDE_INT_MAX, making
it host dependent rather than target dependent.  Either it should work with
HWI and its max always, or should cap at precision of some target type
(e.g. glibc I think uses int type for both width and precision, parsing
through read_int that is similar to target_strtol10, except that it returns
(target) int and if over INT_MAX uses -1).

	Jakub

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993)
  2019-02-23  0:27         ` Jakub Jelinek
@ 2019-02-23  1:02           ` Martin Sebor
  0 siblings, 0 replies; 9+ messages in thread
From: Martin Sebor @ 2019-02-23  1:02 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 2/22/19 4:33 PM, Jakub Jelinek wrote:
> On Fri, Feb 22, 2019 at 04:17:14PM -0700, Martin Sebor wrote:
>> On 2/22/19 3:44 PM, Jakub Jelinek wrote:
>>> On Tue, Feb 19, 2019 at 05:43:53PM -0700, Martin Sebor wrote:
>>>> 	PR tree-optimization/88993
>>>> 	PR tree-optimization/88835
>>>> 	* 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.
>>>
>>> Can you please, when testing a patch like this where you should expect
>>> tbe wordsize will play an important role to test it with
>>> make check-gcc RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} tree-ssa.exp=builtin-*printf-warn*'
>>> ?
>>> There are many failures on ilp32 targets.
>>>
>>> +FAIL: gcc.dg/tree-ssa/builtin-fprintf-warn-2.c  (test for warnings, line 114)
>>
>> I don't see these failures with -m32.  They must be specific to 32-bit
>> GCC itself.
> 
> My bootstrap was indeed i686-linux, not x86_64-linux compiler with -m32.
> E.g. target_strtol10 for some strange reason returns long rather than
> HOST_WIDE_INT and checks LONG_MAX rather than HOST_WIDE_INT_MAX, making
> it host dependent rather than target dependent.  Either it should work with
> HWI and its max always, or should cap at precision of some target type
> (e.g. glibc I think uses int type for both width and precision, parsing
> through read_int that is similar to target_strtol10, except that it returns
> (target) int and if over INT_MAX uses -1).

target_strtol10 returns long because it's wide enough for what it's
used for (width and precision, both int) for all supported hosts
and targets.  What it's not good enough for (and what I forgot about)
is capturing the value of width and precision in excess of host
LONG_MAX in diagnostics.  For instance

   printf ("%2147483650i", 1);

in LP64 results in

    warning: ‘%2147483650i’ directive output of 2147483650 bytes exceeds 
‘INT_MAX’

but in ILP32 in:

   warning: ‘%2147483650i’ directive width out of range

But changing the function to work with HOST_WIDE_INT makes
the warnings consistent between the data models and will help
avoid these gotchas in the future so I've made the change.  I'll
post the patch once it passes bootstrap/regtest.

Martin

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-02-23  0:29 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-05  3:58 [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993) Martin Sebor
2019-02-05  5:06 ` Eric Gallager
2019-02-11 18:24 ` Martin Sebor
2019-02-20  0:44   ` PING " Martin Sebor
2019-02-21 19:08     ` Jeff Law
2019-02-22 23:17     ` Jakub Jelinek
2019-02-22 23:33       ` Martin Sebor
2019-02-23  0:27         ` Jakub Jelinek
2019-02-23  1:02           ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).