PR tree-optimization/78913 - Probably misleading error reported by -Wformat-length
authorMartin Sebor <msebor@redhat.com>
Sun, 8 Jan 2017 23:42:09 +0000 (23:42 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Sun, 8 Jan 2017 23:42:09 +0000 (16:42 -0700)
PR tree-optimization/78913 - Probably misleading error reported by -Wformat-length
PR middle-end/77708 - -Wformat-length %s warns for snprintf

gcc/ChangeLog:

PR middle-end/77708
* doc/invoke.texi (Warning Options): Document -Wformat-truncation.
* gimple-ssa-sprintf.c (call_info::reval_used, call_info::warnopt):
New member functions.
(format_directive): Used them.
(add_bytes): Same.
(pass_sprintf_length::handle_gimple_call): Same.
* graphite-sese-to-poly.c (tree_int_to_gmp): Increase buffer size
to avoid truncation for any argument.
(extract_affine_mul): Same.
* tree.c (get_file_function_name): Same.

gcc/c-family/ChangeLog:

PR middle-end/77708
* c.opt (-Wformat-truncation): New option.

gcc/fortran/ChangeLog:

PR tree-optimization/78913
PR middle-end/77708
* trans-common.c (build_equiv_decl): Increase buffer size to avoid
truncation for any argument.
* trans-types.c (gfc_build_logical_type): Same.

gcc/testsuite/ChangeLog:

PR middle-end/77708
* gcc.dg/tree-ssa/builtin-snprintf-warn-1.c: New test.
* gcc.dg/tree-ssa/builtin-snprintf-warn-2.c: New test.
* gcc.dg/tree-ssa/builtin-sprintf-warn-6.c: XFAIL test cases failing
due to bug 78969.
* gcc.dg/format/pr78569.c: Adjust.

From-SVN: r244210

15 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/doc/invoke.texi
gcc/fortran/ChangeLog
gcc/fortran/trans-common.c
gcc/fortran/trans-types.c
gcc/gimple-ssa-sprintf.c
gcc/graphite-sese-to-poly.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format/pr78569.c
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-6.c
gcc/tree.c

index 375b79a83c5687d3acd8610d0572c689cf149d8e..9c2661ba58b8fa6b30f6b3d7d45b690137ef92ab 100644 (file)
@@ -1,3 +1,17 @@
+2017-01-08  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/77708
+       * doc/invoke.texi (Warning Options): Document -Wformat-truncation.
+       * gimple-ssa-sprintf.c (call_info::reval_used, call_info::warnopt):
+       New member functions.
+       (format_directive): Used them.
+       (add_bytes): Same.
+       (pass_sprintf_length::handle_gimple_call): Same.
+       * graphite-sese-to-poly.c (tree_int_to_gmp): Increase buffer size
+       to avoid truncation for any argument.
+       (extract_affine_mul): Same.
+       * tree.c (get_file_function_name): Same.
+
 2017-01-01  Jan Hubicka  <hubicka@ucw.cz>
 
        PR middle-end/77484
index 375dad193589caad85623e3d7d341b6e6b733c0a..3bd2c7ce88e9e5c3e9464433e62307fa612bf4cf 100644 (file)
@@ -1,3 +1,8 @@
+2017-01-08  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/77708
+       * c.opt (-Wformat-truncation): New option.
+
 2017-01-06  Alexandre Oliva <aoliva@redhat.com>
 
        * c-pretty-print.c (pp_c_tree_decl_identifier): Convert 16-bit
index 0b74aba2f036682ce6dc3ae7f248ff8e8e9b891f..8b2fc79f8ab29d317d0651699784843615dc350c 100644 (file)
@@ -537,6 +537,11 @@ Wformat-signedness
 C ObjC C++ ObjC++ Var(warn_format_signedness) Warning
 Warn about sign differences with format functions.
 
+Wformat-truncation
+C ObjC C++ ObjC++ Warning Alias(Wformat-truncation=, 1, 0)
+Warn about calls to snprintf and similar functions that truncate output.
+Same as -Wformat-truncation=1.
+
 Wformat-y2k
 C ObjC C++ ObjC++ Var(warn_format_y2k) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=,warn_format >= 2, 0)
 Warn about strftime formats yielding 2-digit years.
@@ -554,6 +559,10 @@ C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_format_length) Warning
 Warn about function calls with format strings that write past the end
 of the destination region.
 
+Wformat-truncation=
+C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_format_trunc) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 1, 0)
+Warn about calls to snprintf and similar functions that truncate output.
+
 Wignored-qualifiers
 C C++ Var(warn_ignored_qualifiers) Warning EnabledBy(Wextra)
 Warn whenever type qualifiers are ignored.
index d954f52db91a6997f13214d0cb1781635c777c01..6cf03ef95e42c866e9c94b5858dae62b9f7f3ef7 100644 (file)
@@ -276,7 +276,8 @@ Objective-C and Objective-C++ Dialects}.
 -Werror  -Werror=* -Wfatal-errors -Wfloat-equal  -Wformat  -Wformat=2 @gol
 -Wno-format-contains-nul -Wno-format-extra-args -Wformat-length=@var{n} @gol
 -Wformat-nonliteral @gol
--Wformat-security  -Wformat-signedness  -Wformat-y2k -Wframe-address @gol
+-Wformat-security  -Wformat-signedness -Wformat-truncation=@var{n} @gol
+-Wformat-y2k -Wframe-address @gol
 -Wframe-larger-than=@var{len} -Wno-free-nonheap-object -Wjump-misses-init @gol
 -Wignored-qualifiers  -Wignored-attributes  -Wincompatible-pointer-types @gol
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n} @gol
@@ -3959,10 +3960,9 @@ Unix Specification says that such unused arguments are allowed.
 @opindex Wformat-length
 @opindex Wno-format-length
 Warn about calls to formatted input/output functions such as @code{sprintf}
-that might overflow the destination buffer, or about bounded functions such
-as @code{snprintf} that might result in output truncation.  When the exact
-number of bytes written by a format directive cannot be determined at
-compile-time it is estimated based on heuristics that depend on the
+and @code{vsprintf} that might overflow the destination buffer.  When the
+exact number of bytes written by a format directive cannot be determined
+at compile-time it is estimated based on heuristics that depend on the
 @var{level} argument and on optimization.  While enabling optimization
 will in most cases improve the accuracy of the warning, it may also
 result in false positives.
@@ -3974,15 +3974,14 @@ result in false positives.
 @opindex Wno-format-length
 Level @var{1} of @option{-Wformat-length} enabled by @option{-Wformat}
 employs a conservative approach that warns only about calls that most
-likely overflow the buffer or result in output truncation.  At this
-level, numeric arguments to format directives with unknown values are
-assumed to have the value of one, and strings of unknown length to be
-empty.  Numeric arguments that are known to be bounded to a subrange
-of their type, or string arguments whose output is bounded either by
-their directive's precision or by a finite set of string literals, are
-assumed to take on the value within the range that results in the most
-bytes on output.  For example, the call to @code{sprintf} below is
-diagnosed because even with both @var{a} and @var{b} equal to zero,
+likely overflow the buffer.  At this level, numeric arguments to format
+directives with unknown values are assumed to have the value of one, and
+strings of unknown length to be empty.  Numeric arguments that are known
+to be bounded to a subrange of their type, or string arguments whose output
+is bounded either by their directive's precision or by a finite set of
+string literals, are assumed to take on the value within the range that
+results in the most bytes on output.  For example, the call to @code{sprintf}
+below is diagnosed because even with both @var{a} and @var{b} equal to zero,
 the terminating NUL character (@code{'\0'}) appended by the function
 to the destination buffer will be written past its end.  Increasing
 the size of the buffer by a single byte is sufficient to avoid the
@@ -3998,14 +3997,13 @@ void f (int a, int b)
 
 @item -Wformat-length=2
 Level @var{2} warns also about calls that might overflow the destination
-buffer or result in truncation given an argument of sufficient length
-or magnitude.  At level @var{2}, unknown numeric arguments are assumed
-to have the minimum representable value for signed types with a precision
-greater than 1, and the maximum representable value otherwise.  Unknown
-string arguments whose length cannot be assumed to be bounded either by
-the directive's precision, or by a finite set of string literals they
-may evaluate to, or the character array they may point to, are assumed
-to be 1 character long.
+buffer given an argument of sufficient length or magnitude.  At level
+@var{2}, unknown numeric arguments are assumed to have the minimum
+representable value for signed types with a precision greater than 1, and
+the maximum representable value otherwise.  Unknown string arguments whose
+length cannot be assumed to be bounded either by the directive's precision,
+or by a finite set of string literals they may evaluate to, or the character
+array they may point to, are assumed to be 1 character long.
 
 At level @var{2}, the call in the example above is again diagnosed, but
 this time because with @var{a} equal to a 32-bit @code{INT_MIN} the first
@@ -4075,6 +4073,35 @@ included in @option{-Wformat-nonliteral}.)
 If @option{-Wformat} is specified, also warn if the format string
 requires an unsigned argument and the argument is signed and vice versa.
 
+@item -Wformat-truncation
+@itemx -Wformat-truncation=@var{level}
+@opindex Wformat-truncation
+@opindex Wno-format-truncation
+Warn about calls to formatted input/output functions such as @code{snprintf}
+and @code{vsnprintf} that might result in output truncation.  When the exact
+number of bytes written by a format directive cannot be determined at
+compile-time it is estimated based on heuristics that depend on
+the @var{level} argument and on optimization.  While enabling optimization
+will in most cases improve the accuracy of the warning, it may also result
+in false positives.  Except as noted otherwise, the option uses the same
+logic @option{-Wformat-length}.
+
+@table @gcctabopt
+@item -Wformat-truncation
+@item -Wformat-truncation=1
+@opindex Wformat-truncation
+@opindex Wno-format-length
+Level @var{1} of @option{-Wformat-truncation} enabled by @option{-Wformat}
+employs a conservative approach that warns only about calls to bounded
+functions whose return value is unused and that will most likely result
+in output truncatation.
+
+@item -Wformat-truncation=2
+Level @var{2} warns also about calls to bounded functions whose return
+value is used and that might result in truncation given an argument of
+sufficient length or magnitude.
+@end table
+
 @item -Wformat-y2k
 @opindex Wformat-y2k
 @opindex Wno-format-y2k
@@ -8429,8 +8456,8 @@ if (snprintf (buf, "%08x", i) >= sizeof buf)
 
 The @option{-fprintf-return-value} option relies on other optimizations
 and yields best results with @option{-O2}.  It works in tandem with the
-@option{-Wformat-length} option.  The @option{-fprintf-return-value}
-option is enabled by default.
+@option{-Wformat-length} and @option{-Wformat-truncation} options.
+The @option{-fprintf-return-value} option is enabled by default.
 
 @item -fno-peephole
 @itemx -fno-peephole2
index f89f9fd9972487caafdf711cd5eee8f71915c6e2..36e45555c5a4b7ec3d95c833771436d843436bfc 100644 (file)
@@ -1,3 +1,11 @@
+2017-01-08  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/78913
+       PR middle-end/77708
+       * trans-common.c (build_equiv_decl): Increase buffer size to avoid
+       truncation for any argument.
+       * trans-types.c (gfc_build_logical_type): Same.
+
 2017-01-07  Andre Vehreschild  <vehre@gcc.gnu.org>
 
        PR fortran/78781
index 3068feef38d8375ec76c3226dc0c9b09ca7c75a3..36370ebc22b324122fba9a6f67e45e3850db560c 100644 (file)
@@ -342,7 +342,7 @@ static tree
 build_equiv_decl (tree union_type, bool is_init, bool is_saved)
 {
   tree decl;
-  char name[15];
+  char name[18];
   static int serial = 0;
 
   if (is_init)
index 156c0dac15d06d66cca415ac0c71f153757bc276..759b80eecaa044daf2f77d14d96e591c007dbe4d 100644 (file)
@@ -861,7 +861,7 @@ gfc_build_logical_type (gfc_logical_info *info)
 void
 gfc_init_types (void)
 {
-  char name_buf[18];
+  char name_buf[26];
   int index;
   tree type;
   unsigned n;
index 6a9f679f8131bb313e672f3a5049e468714abac4..166b34ba37e1dc0da3e6c46c04c12df5db0e88c8 100644 (file)
@@ -718,6 +718,18 @@ struct pass_sprintf_length::call_info
      writing any.  NOWRITE is cleared in response to the %n directive
      which has side-effects similar to writing output.  */
   bool nowrite;
+
+  /* Return true if the called function's return value is used.  */
+  bool retval_used () const
+  {
+    return gimple_get_lhs (callstmt);
+  }
+
+  /* Return the warning option corresponding to the called function.  */
+  int warnopt () const
+  {
+    return bounded ? OPT_Wformat_truncation_ : OPT_Wformat_length_;
+  }
 };
 
 /* Return the result of formatting the '%%' directive.  */
@@ -1950,8 +1962,7 @@ format_directive (const pass_sprintf_length::call_info &info,
 
   if (fmtres.nullp)
     {
-      fmtwarn (dirloc, pargrange, NULL,
-              OPT_Wformat_length_,
+      fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
               "%<%.*s%> directive argument is null",
               (int)cvtlen, cvtbeg);
 
@@ -1986,8 +1997,8 @@ format_directive (const pass_sprintf_length::call_info &info,
                            "%wu bytes into a region of size %wu")
                       : G_("%<%.*s%> directive writing %wu bytes "
                            "into a region of size %wu"));
-                 warned = fmtwarn (dirloc, pargrange, NULL,
-                                   OPT_Wformat_length_, fmtstr,
+                 warned = fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
+                                   fmtstr,
                                    (int)cvtlen, cvtbeg, fmtres.range.min,
                                    navail);
                }
@@ -2001,7 +2012,7 @@ format_directive (const pass_sprintf_length::call_info &info,
                       : G_("%<%.*s%> directive writing between %wu and "
                            "%wu bytes into a region of size %wu"));
                  warned = fmtwarn (dirloc, pargrange, NULL,
-                                   OPT_Wformat_length_, fmtstr,
+                                   info.warnopt (), fmtstr,
                                    (int)cvtlen, cvtbeg,
                                    fmtres.range.min, fmtres.range.max, navail);
                }
@@ -2014,16 +2025,20 @@ format_directive (const pass_sprintf_length::call_info &info,
                       : G_("%<%.*s%> directive writing %wu or more bytes "
                            "into a region of size %wu"));
                  warned = fmtwarn (dirloc, pargrange, NULL,
-                                   OPT_Wformat_length_, fmtstr,
+                                   info.warnopt (), fmtstr,
                                    (int)cvtlen, cvtbeg,
                                    fmtres.range.min, navail);
                }
            }
          else if (navail < fmtres.range.max
-                  && (((spec.specifier == 's'
-                        && fmtres.range.max < HOST_WIDE_INT_MAX)
-                       /* && (spec.precision || spec.star_precision) */)
-                      || 1 < warn_format_length))
+                  && (spec.specifier != 's'
+                      || fmtres.range.max < HOST_WIDE_INT_MAX)
+                  && ((info.bounded
+                       && (!info.retval_used ()
+                           || warn_format_trunc > 1))
+                      || (!info.bounded
+                          && (spec.specifier == 's'
+                              || 1 < warn_format_length))))
            {
              /* The maximum directive output is longer than there is
                 room in the destination and the output length is either
@@ -2038,7 +2053,7 @@ format_directive (const pass_sprintf_length::call_info &info,
                       : G_("%<%.*s%> directive writing %wu or more bytes "
                            "into a region of size %wu"));
                  warned = fmtwarn (dirloc, pargrange, NULL,
-                                   OPT_Wformat_length_, fmtstr,
+                                   info.warnopt (), fmtstr,
                                    (int)cvtlen, cvtbeg,
                                    fmtres.range.min, navail);
                }
@@ -2052,7 +2067,7 @@ format_directive (const pass_sprintf_length::call_info &info,
                       : G_("%<%.*s%> directive writing between %wu and %wu "
                            "bytes into a region of size %wu"));
                  warned = fmtwarn (dirloc, pargrange, NULL,
-                                   OPT_Wformat_length_, fmtstr,
+                                   info.warnopt (), fmtstr,
                                    (int)cvtlen, cvtbeg,
                                    fmtres.range.min, fmtres.range.max,
                                    navail);
@@ -2086,7 +2101,7 @@ format_directive (const pass_sprintf_length::call_info &info,
                       "into a region of size %wu")));
 
          warned = fmtwarn (dirloc, pargrange, NULL,
-                           OPT_Wformat_length_, fmtstr,
+                           info.warnopt (), fmtstr,
                            (int)cvtlen, cvtbeg, fmtres.range.min,
                            navail);
        }
@@ -2111,7 +2126,7 @@ format_directive (const pass_sprintf_length::call_info &info,
 
       if (fmtres.range.min == fmtres.range.max)
        warned = fmtwarn (dirloc, pargrange, NULL,
-                         OPT_Wformat_length_,
+                         info.warnopt (),
                          "%<%.*s%> directive output of %wu bytes exceeds "
                          "minimum required size of 4095",
                          (int)cvtlen, cvtbeg, fmtres.range.min);
@@ -2125,7 +2140,7 @@ format_directive (const pass_sprintf_length::call_info &info,
                    "bytes exceeds minimum required size of 4095"));
 
          warned = fmtwarn (dirloc, pargrange, NULL,
-                           OPT_Wformat_length_, fmtstr,
+                           info.warnopt (), fmtstr,
                            (int)cvtlen, cvtbeg,
                            fmtres.range.min, fmtres.range.max);
        }
@@ -2143,8 +2158,7 @@ format_directive (const pass_sprintf_length::call_info &info,
         to exceed INT_MAX bytes.  */
 
       if (fmtres.range.min == fmtres.range.max)
-       warned = fmtwarn (dirloc, pargrange, NULL,
-                         OPT_Wformat_length_,
+       warned = fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
                          "%<%.*s%> directive output of %wu bytes causes "
                          "result to exceed %<INT_MAX%>",
                          (int)cvtlen, cvtbeg, fmtres.range.min);
@@ -2157,7 +2171,7 @@ format_directive (const pass_sprintf_length::call_info &info,
               : G_ ("%<%.*s%> directive output between %wu and %wu "
                     "bytes may cause result to exceed %<INT_MAX%>"));
          warned = fmtwarn (dirloc, pargrange, NULL,
-                           OPT_Wformat_length_, fmtstr,
+                           info.warnopt (), fmtstr,
                            (int)cvtlen, cvtbeg,
                            fmtres.range.min, fmtres.range.max);
        }
@@ -2265,7 +2279,11 @@ add_bytes (const pass_sprintf_length::call_info &info,
                  : G_("writing a terminating nul past the end "
                       "of the destination")));
 
-         res->warned = fmtwarn (loc, NULL, NULL, OPT_Wformat_length_, text);
+         if (!info.bounded
+             || !boundrange
+             || !info.retval_used ()
+             || warn_format_trunc > 1)
+           res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (), text);
        }
       else
        {
@@ -2283,8 +2301,12 @@ add_bytes (const pass_sprintf_length::call_info &info,
                  : G_("writing format character %#qc at offset %wu past "
                       "the end of the destination")));
 
-         res->warned = fmtwarn (loc, NULL, NULL, OPT_Wformat_length_,
-                                text, info.fmtstr[off], off);
+         if (!info.bounded
+             || !boundrange
+             || !info.retval_used ()
+             || warn_format_trunc > 1)
+           res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (),
+                                  text, info.fmtstr[off], off);
        }
     }
 
@@ -2351,8 +2373,7 @@ add_bytes (const pass_sprintf_length::call_info &info,
         off + len - !!len);
 
       if (res->number_chars_min == res->number_chars_max)
-       res->warned = fmtwarn (loc, NULL, NULL,
-                              OPT_Wformat_length_,
+       res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (),
                               "output of %wu bytes causes "
                               "result to exceed %<INT_MAX%>",
                               res->number_chars_min - !end);
@@ -2364,8 +2385,7 @@ add_bytes (const pass_sprintf_length::call_info &info,
                     "result to exceed %<INT_MAX%>")
               : G_ ("output between %wu and %wu bytes may cause "
                     "result to exceed %<INT_MAX%>"));
-         res->warned = fmtwarn (loc, NULL, NULL, OPT_Wformat_length_,
-                                text,
+         res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (), text,
                                 res->number_chars_min - !end,
                                 res->number_chars_max - !end);
        }
@@ -2970,14 +2990,13 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
                 checking built-ins.  */
              if ((idx_objsize == HOST_WIDE_INT_M1U
                   || !warn_stringop_overflow))
-               warning_at (gimple_location (info.callstmt),
-                           OPT_Wformat_length_,
+               warning_at (gimple_location (info.callstmt), info.warnopt (),
                            "specified bound %wu exceeds maximum object size "
                            "%wu",
                            dstsize, target_size_max () / 2);
            }
          else if (dstsize > target_int_max ())
-           warning_at (gimple_location (info.callstmt), OPT_Wformat_length_,
+           warning_at (gimple_location (info.callstmt), info.warnopt (),
                        "specified bound %wu exceeds %<INT_MAX %>",
                        dstsize);
        }
@@ -3028,7 +3047,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
             is not constant.  */
          location_t loc = gimple_location (info.callstmt);
          warning_at (EXPR_LOC_OR_LOC (dstptr, loc),
-                     OPT_Wformat_length_, "null destination pointer");
+                     info.warnopt (), "null destination pointer");
          return;
        }
 
@@ -3044,7 +3063,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
          && (idx_objsize == HOST_WIDE_INT_M1U
              || !warn_stringop_overflow))
        {
-         warning_at (gimple_location (info.callstmt), OPT_Wformat_length_,
+         warning_at (gimple_location (info.callstmt), info.warnopt (),
                      "specified bound %wu exceeds the size %wu "
                      "of the destination object", dstsize, objsize);
        }
@@ -3057,7 +3076,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
         is not constant.  */
       location_t loc = gimple_location (info.callstmt);
       warning_at (EXPR_LOC_OR_LOC (info.format, loc),
-                 OPT_Wformat_length_, "null format string");
+                 info.warnopt (), "null format string");
       return;
     }
 
index 2af50b5b394f107615f61eb59d477755e0a40b8e..fa224edff94fee3cb589f0c599313aba35f8b960 100644 (file)
@@ -72,7 +72,7 @@ tree_int_to_gmp (tree t, mpz_t res)
 static isl_id *
 isl_id_for_pbb (scop_p s, poly_bb_p pbb)
 {
-  char name[10];
+  char name[14];
   snprintf (name, sizeof (name), "S_%d", pbb_index (pbb));
   return isl_id_alloc (s->isl_context, name, pbb);
 }
@@ -271,7 +271,7 @@ extract_affine_mul (scop_p s, tree e, __isl_take isl_space *space)
 static isl_id *
 isl_id_for_ssa_name (scop_p s, tree e)
 {
-  char name1[10];
+  char name1[14];
   snprintf (name1, sizeof (name1), "P_%d", SSA_NAME_VERSION (e));
   return isl_id_alloc (s->isl_context, name1, e);
 }
index 1f6100bd323e59ff319d31b2802b171690d389f7..fc3873578f686f1aeeaa60280001af36306d3924 100644 (file)
@@ -1,3 +1,12 @@
+2017-01-08  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/77708
+       * gcc.dg/tree-ssa/builtin-snprintf-warn-1.c: New test.
+       * gcc.dg/tree-ssa/builtin-snprintf-warn-2.c: New test.
+       * gcc.dg/tree-ssa/builtin-sprintf-warn-6.c: XFAIL test cases failing
+       due to bug 78969.
+       * gcc.dg/format/pr78569.c: Adjust.
+
 2017-01-07  David Malcolm  <dmalcolm@redhat.com>
 
        PR c++/72803
index e827087e1c3c09679778c1c014ae49ac6049df6e..c2b239b579b14486a1d99e6b7e35718c6a2b2f0a 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-Wformat-length" } */
+/* { dg-options "-Wformat-truncation" } */
 
 /* A run of blank lines, so that we would fail the assertion in input.c:1388:
    gcc_assert (line_width >= (start.column - 1 + literal_length));  */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c
new file mode 100644 (file)
index 0000000..cc226ca
--- /dev/null
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wformat -Wformat-truncation=1 -ftrack-macro-expansion=0" } */
+
+typedef struct
+{
+  char a0[0];
+  char a1[1];
+  char a2[2];
+  char a3[3];
+  char a4[4];
+  char ax[];
+} Arrays;
+
+char buffer[1024];
+#define buffer(size) (buffer + sizeof buffer - size)
+
+int value_range (int min, int max)
+{
+  extern int value (void);
+  int val = value ();
+  return val < min || max < val ? min : val;
+}
+
+#define R(min, max)  value_range (min, max)
+
+/* Verify that calls to snprintf whose return value is unused are
+   diagnosed if certain or possible truncation is detected.  */
+
+#define T(size, ...) \
+  __builtin_snprintf (buffer (size), size, __VA_ARGS__)
+
+void test_int_retval_unused (void)
+{
+  T (2, "%i", 123);          /* { dg-warning "output truncated" } */
+  T (2, "%i", R (1, 99));    /* { dg-warning "output may be truncated" } */
+  T (2, "%i", R (10, 99));   /* { dg-warning "output truncated" } */
+  T (3, "%i%i", R (1, 99), R (1, 99));   /* { dg-warning "output may be truncated" } */
+}
+
+void test_string_retval_unused (const Arrays *ar)
+{
+  T (1, "%-s", ar->a0);
+  T (1, "%-s", ar->a1);
+  T (1, "%-s", ar->a2);   /* { dg-warning "output may be truncated" } */
+}
+
+
+/* Verify that calls to snprintf whose return value is used are
+   diagnosed only if certain truncation is detected but not when
+   truncation is only possible but not certain.  */
+
+volatile int retval;
+
+#undef T
+#define T(size, ...) \
+  retval = __builtin_snprintf (buffer (size), size, __VA_ARGS__)
+
+void test_int_retval_used (void)
+{
+  T (2, "%i", 123);          /* { dg-warning "output truncated" } */
+  T (2, "%i", R (1, 99));
+  T (2, "%i", R (10, 99));   /* { dg-warning "output truncated" } */
+  T (3, "%i%i", R (1, 99), R (1, 99));
+}
+
+void test_string_retval_used (const Arrays *ar)
+{
+  T (1, "%-s", ar->a0);
+  T (1, "%-s", ar->a1);
+  T (1, "%-s", ar->a2);
+  T (1, "%-s", ar->a4);
+  T (1, "%-s", "123");   /* { dg-warning "output truncated" } */
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c
new file mode 100644 (file)
index 0000000..93c9f1b
--- /dev/null
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wformat -Wformat-truncation=2 -ftrack-macro-expansion=0" } */
+
+typedef struct
+{
+  char a0[0];
+  char a1[1];
+  char a2[2];
+  char a3[3];
+  char a4[4];
+  char ax[];
+} Arrays;
+
+char buffer[1024];
+#define buffer(size) (buffer + sizeof buffer - size)
+
+int value_range (int min, int max)
+{
+  extern int value (void);
+  int val = value ();
+  return val < min || max < val ? min : val;
+}
+
+#define R(min, max)  value_range (min, max)
+
+/* Verify that calls to snprintf whose return value is unused are
+   diagnosed if certain or possible truncation is detected.  */
+
+#define T(size, ...) \
+  __builtin_snprintf (buffer (size), size, __VA_ARGS__)
+
+void test_int_retval_unused (void)
+{
+  T (2, "%i", 123);          /* { dg-warning "output truncated" } */
+  T (2, "%i", R (1, 99));    /* { dg-warning "output may be truncated" } */
+  T (2, "%i", R (10, 99));   /* { dg-warning "output truncated" } */
+  T (3, "%i%i", R (1, 99), R (1, 99));   /* { dg-warning "output may be truncated" } */
+}
+
+void test_string_retval_unused (const Arrays *ar)
+{
+  T (1, "%-s", ar->a0);
+  T (1, "%-s", ar->a1);
+  T (1, "%-s", ar->a2);   /* { dg-warning "output may be truncated" } */
+}
+
+
+/* Verify that (at -Wformat-trunc=2) calls to snprintf whose return value
+   is used are diagnosed the same way as those whose value is unused.  */
+
+volatile int retval;
+
+#undef T
+#define T(size, ...) \
+  retval = __builtin_snprintf (buffer (size), size, __VA_ARGS__)
+
+void test_int_retval_used (void)
+{
+  T (2, "%i", 123);          /* { dg-warning "output truncated" } */
+  T (2, "%i", R (1, 99));    /* { dg-warning "output may be truncated" } */
+  T (2, "%i", R (10, 99));   /* { dg-warning "output truncated" } */
+  T (3, "%i%i", R (1, 99), R (1, 99));   /* { dg-warning "output may be truncated" } */
+}
+
+void test_string_retval_used (const Arrays *ar)
+{
+  T (1, "%-s", ar->a0);
+  T (1, "%-s", ar->a1);
+  T (1, "%-s", ar->a2);   /* { dg-warning "output may be truncated" } */
+}
index 121ed4ea3c822ec76187fc155f87308507e21c23..93c53a409fc0c95518e97c5651c4c91b7bdc79bf 100644 (file)
@@ -51,7 +51,8 @@ void fuint (unsigned j, char *p)
 {
   if (j > 999)
     return;
-  snprintf (p, 4, "%3u", j);
+
+  snprintf (p, 4, "%3u", j);   /* { dg-bogus "may be truncated" "unsigned int" { xfail *-*-* } } */
 }
 
 void fint (int j, char *p)
@@ -61,8 +62,7 @@ void fint (int j, char *p)
   if (k > 999)
     return;
 
-  /* Range info isn't available here.  */
-  snprintf (p, 4, "%3u", k);
+  snprintf (p, 4, "%3u", k);   /* { dg-bogus "may be truncated" "signed int" { xfail *-*-* } } */
 }
 
 void fulong (unsigned long j, char *p)
@@ -70,8 +70,7 @@ void fulong (unsigned long j, char *p)
   if (j > 999)
     return;
 
-  /* Range info isn't available here.  */
-  snprintf (p, 4, "%3lu", j);
+  snprintf (p, 4, "%3lu", j);   /* { dg-bogus "may be truncated" "unsigned long" { xfail *-*-* } } */
 }
 
 void flong (long j, char *p)
@@ -81,8 +80,7 @@ void flong (long j, char *p)
   if (k > 999)
     return;
 
-  /* Range info isn't available here.  */
-  snprintf (p, 4, "%3lu", k);
+  snprintf (p, 4, "%3lu", k);   /* { dg-bogus "may be truncated" "signed long" { xfail *-*-* } } */
 }
 
 void fullong (unsigned long long j, char *p)
@@ -90,18 +88,17 @@ void fullong (unsigned long long j, char *p)
   if (j > 999)
     return;
 
-  /* Range info isn't available here.  */
-  snprintf (p, 4, "%3llu", j);
+  snprintf (p, 4, "%3llu", j);   /* { dg-bogus "may be truncated" "signed long" { xfail *-*-* } } */
 }
 
-void fllong (long j, char *p)
+void fllong (long long j, char *p)
 {
   const unsigned long long k = (unsigned long long) j;
 
   if (k > 999)
     return;
 
-  snprintf (p, 4, "%3llu", k);
+  snprintf (p, 4, "%3llu", k);   /* { dg-bogus "may be truncated" "unsigned long long" { xfail *-*-* } } */
 }
 
 /* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
index 193430105aa271d284d0001144897cc53b042089..7c030fa85a4ac2872cfb71ff4d0570106858c8aa 100644 (file)
@@ -9746,10 +9746,10 @@ get_file_function_name (const char *type)
        file = LOCATION_FILE (input_location);
 
       len = strlen (file);
-      q = (char *) alloca (9 + 17 + len + 1);
+      q = (char *) alloca (9 + 19 + len + 1);
       memcpy (q, file, len + 1);
 
-      snprintf (q + len, 9 + 17 + 1, "_%08X_" HOST_WIDE_INT_PRINT_HEX, 
+      snprintf (q + len, 9 + 19 + 1, "_%08X_" HOST_WIDE_INT_PRINT_HEX,
                crc32_string (0, name), get_random_seed (false));
 
       p = q;