From efcc8d387f52f995a6e41bc78a76cc77e4bb6ee8 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sun, 8 Jan 2017 23:42:09 +0000 Subject: [PATCH] PR tree-optimization/78913 - Probably misleading error reported by -Wformat-length 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 --- gcc/ChangeLog | 14 ++++ gcc/c-family/ChangeLog | 5 ++ gcc/c-family/c.opt | 9 +++ gcc/doc/invoke.texi | 75 +++++++++++------ gcc/fortran/ChangeLog | 8 ++ gcc/fortran/trans-common.c | 2 +- gcc/fortran/trans-types.c | 2 +- gcc/gimple-ssa-sprintf.c | 81 ++++++++++++------- gcc/graphite-sese-to-poly.c | 4 +- gcc/testsuite/ChangeLog | 9 +++ gcc/testsuite/gcc.dg/format/pr78569.c | 2 +- .../gcc.dg/tree-ssa/builtin-snprintf-warn-1.c | 73 +++++++++++++++++ .../gcc.dg/tree-ssa/builtin-snprintf-warn-2.c | 70 ++++++++++++++++ .../gcc.dg/tree-ssa/builtin-sprintf-warn-6.c | 19 ++--- gcc/tree.c | 4 +- 15 files changed, 304 insertions(+), 73 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 375b79a83c5..9c2661ba58b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2017-01-08 Martin Sebor + + 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 PR middle-end/77484 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 375dad19358..3bd2c7ce88e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2017-01-08 Martin Sebor + + PR middle-end/77708 + * c.opt (-Wformat-truncation): New option. + 2017-01-06 Alexandre Oliva * c-pretty-print.c (pp_c_tree_decl_identifier): Convert 16-bit diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 0b74aba2f03..8b2fc79f8ab 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -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. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d954f52db91..6cf03ef95e4 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f89f9fd9972..36e45555c5a 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,11 @@ +2017-01-08 Martin Sebor + + 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 PR fortran/78781 diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c index 3068feef38d..36370ebc22b 100644 --- a/gcc/fortran/trans-common.c +++ b/gcc/fortran/trans-common.c @@ -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) diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 156c0dac15d..759b80eecaa 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -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; diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index 6a9f679f813..166b34ba37e 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -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)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 %")); 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 %", res->number_chars_min - !end); @@ -2364,8 +2385,7 @@ add_bytes (const pass_sprintf_length::call_info &info, "result to exceed %") : G_ ("output between %wu and %wu bytes may cause " "result to exceed %")); - 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 %", 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; } diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c index 2af50b5b394..fa224edff94 100644 --- a/gcc/graphite-sese-to-poly.c +++ b/gcc/graphite-sese-to-poly.c @@ -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); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1f6100bd323..fc3873578f6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2017-01-08 Martin Sebor + + 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 PR c++/72803 diff --git a/gcc/testsuite/gcc.dg/format/pr78569.c b/gcc/testsuite/gcc.dg/format/pr78569.c index e827087e1c3..c2b239b579b 100644 --- a/gcc/testsuite/gcc.dg/format/pr78569.c +++ b/gcc/testsuite/gcc.dg/format/pr78569.c @@ -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 index 00000000000..cc226caad5f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c @@ -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 index 00000000000..93c9f1bebfe --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c @@ -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" } */ +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-6.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-6.c index 121ed4ea3c8..93c53a409fc 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-6.c @@ -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" } } */ diff --git a/gcc/tree.c b/gcc/tree.c index 193430105aa..7c030fa85a4 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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; -- 2.30.2