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
This commit is contained in:
Martin Sebor 2017-01-08 23:42:09 +00:00 committed by Martin Sebor
parent 1243c42d64
commit efcc8d387f
15 changed files with 304 additions and 73 deletions

View 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> 2017-01-01 Jan Hubicka <hubicka@ucw.cz>
PR middle-end/77484 PR middle-end/77484

View 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> 2017-01-06 Alexandre Oliva <aoliva@redhat.com>
* c-pretty-print.c (pp_c_tree_decl_identifier): Convert 16-bit * c-pretty-print.c (pp_c_tree_decl_identifier): Convert 16-bit

View File

@ -537,6 +537,11 @@ Wformat-signedness
C ObjC C++ ObjC++ Var(warn_format_signedness) Warning C ObjC C++ ObjC++ Var(warn_format_signedness) Warning
Warn about sign differences with format functions. 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 Wformat-y2k
C ObjC C++ ObjC++ Var(warn_format_y2k) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=,warn_format >= 2, 0) 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. 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 Warn about function calls with format strings that write past the end
of the destination region. 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 Wignored-qualifiers
C C++ Var(warn_ignored_qualifiers) Warning EnabledBy(Wextra) C C++ Var(warn_ignored_qualifiers) Warning EnabledBy(Wextra)
Warn whenever type qualifiers are ignored. Warn whenever type qualifiers are ignored.

View File

@ -276,7 +276,8 @@ Objective-C and Objective-C++ Dialects}.
-Werror -Werror=* -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol -Werror -Werror=* -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol
-Wno-format-contains-nul -Wno-format-extra-args -Wformat-length=@var{n} @gol -Wno-format-contains-nul -Wno-format-extra-args -Wformat-length=@var{n} @gol
-Wformat-nonliteral @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 -Wframe-larger-than=@var{len} -Wno-free-nonheap-object -Wjump-misses-init @gol
-Wignored-qualifiers -Wignored-attributes -Wincompatible-pointer-types @gol -Wignored-qualifiers -Wignored-attributes -Wincompatible-pointer-types @gol
-Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n} @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 Wformat-length
@opindex Wno-format-length @opindex Wno-format-length
Warn about calls to formatted input/output functions such as @code{sprintf} Warn about calls to formatted input/output functions such as @code{sprintf}
that might overflow the destination buffer, or about bounded functions such and @code{vsprintf} that might overflow the destination buffer. When the
as @code{snprintf} that might result in output truncation. When the exact exact number of bytes written by a format directive cannot be determined
number of bytes written by a format directive cannot be determined at at compile-time it is estimated based on heuristics that depend on the
compile-time it is estimated based on heuristics that depend on the
@var{level} argument and on optimization. While enabling optimization @var{level} argument and on optimization. While enabling optimization
will in most cases improve the accuracy of the warning, it may also will in most cases improve the accuracy of the warning, it may also
result in false positives. result in false positives.
@ -3974,15 +3974,14 @@ result in false positives.
@opindex Wno-format-length @opindex Wno-format-length
Level @var{1} of @option{-Wformat-length} enabled by @option{-Wformat} Level @var{1} of @option{-Wformat-length} enabled by @option{-Wformat}
employs a conservative approach that warns only about calls that most employs a conservative approach that warns only about calls that most
likely overflow the buffer or result in output truncation. At this likely overflow the buffer. At this level, numeric arguments to format
level, numeric arguments to format directives with unknown values are directives with unknown values are assumed to have the value of one, and
assumed to have the value of one, and strings of unknown length to be strings of unknown length to be empty. Numeric arguments that are known
empty. Numeric arguments that are known to be bounded to a subrange to be bounded to a subrange of their type, or string arguments whose output
of their type, or string arguments whose output is bounded either by is bounded either by their directive's precision or by a finite set of
their directive's precision or by a finite set of string literals, are string literals, are assumed to take on the value within the range that
assumed to take on the value within the range that results in the most results in the most bytes on output. For example, the call to @code{sprintf}
bytes on output. For example, the call to @code{sprintf} below is below is diagnosed because even with both @var{a} and @var{b} equal to zero,
diagnosed because even with both @var{a} and @var{b} equal to zero,
the terminating NUL character (@code{'\0'}) appended by the function the terminating NUL character (@code{'\0'}) appended by the function
to the destination buffer will be written past its end. Increasing 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 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 @item -Wformat-length=2
Level @var{2} warns also about calls that might overflow the destination Level @var{2} warns also about calls that might overflow the destination
buffer or result in truncation given an argument of sufficient length buffer given an argument of sufficient length or magnitude. At level
or magnitude. At level @var{2}, unknown numeric arguments are assumed @var{2}, unknown numeric arguments are assumed to have the minimum
to have the minimum representable value for signed types with a precision representable value for signed types with a precision greater than 1, and
greater than 1, and the maximum representable value otherwise. Unknown the maximum representable value otherwise. Unknown string arguments whose
string arguments whose length cannot be assumed to be bounded either by length cannot be assumed to be bounded either by the directive's precision,
the directive's precision, or by a finite set of string literals they or by a finite set of string literals they may evaluate to, or the character
may evaluate to, or the character array they may point to, are assumed array they may point to, are assumed to be 1 character long.
to be 1 character long.
At level @var{2}, the call in the example above is again diagnosed, but 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 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 If @option{-Wformat} is specified, also warn if the format string
requires an unsigned argument and the argument is signed and vice versa. 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 @item -Wformat-y2k
@opindex Wformat-y2k @opindex Wformat-y2k
@opindex Wno-format-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 The @option{-fprintf-return-value} option relies on other optimizations
and yields best results with @option{-O2}. It works in tandem with the and yields best results with @option{-O2}. It works in tandem with the
@option{-Wformat-length} option. The @option{-fprintf-return-value} @option{-Wformat-length} and @option{-Wformat-truncation} options.
option is enabled by default. The @option{-fprintf-return-value} option is enabled by default.
@item -fno-peephole @item -fno-peephole
@itemx -fno-peephole2 @itemx -fno-peephole2

View 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> 2017-01-07 Andre Vehreschild <vehre@gcc.gnu.org>
PR fortran/78781 PR fortran/78781

View File

@ -342,7 +342,7 @@ static tree
build_equiv_decl (tree union_type, bool is_init, bool is_saved) build_equiv_decl (tree union_type, bool is_init, bool is_saved)
{ {
tree decl; tree decl;
char name[15]; char name[18];
static int serial = 0; static int serial = 0;
if (is_init) if (is_init)

View File

@ -861,7 +861,7 @@ gfc_build_logical_type (gfc_logical_info *info)
void void
gfc_init_types (void) gfc_init_types (void)
{ {
char name_buf[18]; char name_buf[26];
int index; int index;
tree type; tree type;
unsigned n; unsigned n;

View File

@ -718,6 +718,18 @@ struct pass_sprintf_length::call_info
writing any. NOWRITE is cleared in response to the %n directive writing any. NOWRITE is cleared in response to the %n directive
which has side-effects similar to writing output. */ which has side-effects similar to writing output. */
bool nowrite; 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. */ /* Return the result of formatting the '%%' directive. */
@ -1950,8 +1962,7 @@ format_directive (const pass_sprintf_length::call_info &info,
if (fmtres.nullp) if (fmtres.nullp)
{ {
fmtwarn (dirloc, pargrange, NULL, fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
OPT_Wformat_length_,
"%<%.*s%> directive argument is null", "%<%.*s%> directive argument is null",
(int)cvtlen, cvtbeg); (int)cvtlen, cvtbeg);
@ -1986,8 +1997,8 @@ format_directive (const pass_sprintf_length::call_info &info,
"%wu bytes into a region of size %wu") "%wu bytes into a region of size %wu")
: G_("%<%.*s%> directive writing %wu bytes " : G_("%<%.*s%> directive writing %wu bytes "
"into a region of size %wu")); "into a region of size %wu"));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
OPT_Wformat_length_, fmtstr, fmtstr,
(int)cvtlen, cvtbeg, fmtres.range.min, (int)cvtlen, cvtbeg, fmtres.range.min,
navail); navail);
} }
@ -2001,7 +2012,7 @@ format_directive (const pass_sprintf_length::call_info &info,
: G_("%<%.*s%> directive writing between %wu and " : G_("%<%.*s%> directive writing between %wu and "
"%wu bytes into a region of size %wu")); "%wu bytes into a region of size %wu"));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, fmtstr, info.warnopt (), fmtstr,
(int)cvtlen, cvtbeg, (int)cvtlen, cvtbeg,
fmtres.range.min, fmtres.range.max, navail); 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 " : G_("%<%.*s%> directive writing %wu or more bytes "
"into a region of size %wu")); "into a region of size %wu"));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, fmtstr, info.warnopt (), fmtstr,
(int)cvtlen, cvtbeg, (int)cvtlen, cvtbeg,
fmtres.range.min, navail); fmtres.range.min, navail);
} }
} }
else if (navail < fmtres.range.max else if (navail < fmtres.range.max
&& (((spec.specifier == 's' && (spec.specifier != 's'
&& fmtres.range.max < HOST_WIDE_INT_MAX) || fmtres.range.max < HOST_WIDE_INT_MAX)
/* && (spec.precision || spec.star_precision) */) && ((info.bounded
|| 1 < warn_format_length)) && (!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 /* The maximum directive output is longer than there is
room in the destination and the output length is either 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 " : G_("%<%.*s%> directive writing %wu or more bytes "
"into a region of size %wu")); "into a region of size %wu"));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, fmtstr, info.warnopt (), fmtstr,
(int)cvtlen, cvtbeg, (int)cvtlen, cvtbeg,
fmtres.range.min, navail); 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 " : G_("%<%.*s%> directive writing between %wu and %wu "
"bytes into a region of size %wu")); "bytes into a region of size %wu"));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, fmtstr, info.warnopt (), fmtstr,
(int)cvtlen, cvtbeg, (int)cvtlen, cvtbeg,
fmtres.range.min, fmtres.range.max, fmtres.range.min, fmtres.range.max,
navail); navail);
@ -2086,7 +2101,7 @@ format_directive (const pass_sprintf_length::call_info &info,
"into a region of size %wu"))); "into a region of size %wu")));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, fmtstr, info.warnopt (), fmtstr,
(int)cvtlen, cvtbeg, fmtres.range.min, (int)cvtlen, cvtbeg, fmtres.range.min,
navail); navail);
} }
@ -2111,7 +2126,7 @@ format_directive (const pass_sprintf_length::call_info &info,
if (fmtres.range.min == fmtres.range.max) if (fmtres.range.min == fmtres.range.max)
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, info.warnopt (),
"%<%.*s%> directive output of %wu bytes exceeds " "%<%.*s%> directive output of %wu bytes exceeds "
"minimum required size of 4095", "minimum required size of 4095",
(int)cvtlen, cvtbeg, fmtres.range.min); (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")); "bytes exceeds minimum required size of 4095"));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, fmtstr, info.warnopt (), fmtstr,
(int)cvtlen, cvtbeg, (int)cvtlen, cvtbeg,
fmtres.range.min, fmtres.range.max); fmtres.range.min, fmtres.range.max);
} }
@ -2143,8 +2158,7 @@ format_directive (const pass_sprintf_length::call_info &info,
to exceed INT_MAX bytes. */ to exceed INT_MAX bytes. */
if (fmtres.range.min == fmtres.range.max) if (fmtres.range.min == fmtres.range.max)
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
OPT_Wformat_length_,
"%<%.*s%> directive output of %wu bytes causes " "%<%.*s%> directive output of %wu bytes causes "
"result to exceed %<INT_MAX%>", "result to exceed %<INT_MAX%>",
(int)cvtlen, cvtbeg, fmtres.range.min); (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 " : G_ ("%<%.*s%> directive output between %wu and %wu "
"bytes may cause result to exceed %<INT_MAX%>")); "bytes may cause result to exceed %<INT_MAX%>"));
warned = fmtwarn (dirloc, pargrange, NULL, warned = fmtwarn (dirloc, pargrange, NULL,
OPT_Wformat_length_, fmtstr, info.warnopt (), fmtstr,
(int)cvtlen, cvtbeg, (int)cvtlen, cvtbeg,
fmtres.range.min, fmtres.range.max); 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 " : G_("writing a terminating nul past the end "
"of the destination"))); "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 else
{ {
@ -2283,8 +2301,12 @@ add_bytes (const pass_sprintf_length::call_info &info,
: G_("writing format character %#qc at offset %wu past " : G_("writing format character %#qc at offset %wu past "
"the end of the destination"))); "the end of the destination")));
res->warned = fmtwarn (loc, NULL, NULL, OPT_Wformat_length_, if (!info.bounded
text, info.fmtstr[off], off); || !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); off + len - !!len);
if (res->number_chars_min == res->number_chars_max) if (res->number_chars_min == res->number_chars_max)
res->warned = fmtwarn (loc, NULL, NULL, res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (),
OPT_Wformat_length_,
"output of %wu bytes causes " "output of %wu bytes causes "
"result to exceed %<INT_MAX%>", "result to exceed %<INT_MAX%>",
res->number_chars_min - !end); res->number_chars_min - !end);
@ -2364,8 +2385,7 @@ add_bytes (const pass_sprintf_length::call_info &info,
"result to exceed %<INT_MAX%>") "result to exceed %<INT_MAX%>")
: G_ ("output between %wu and %wu bytes may cause " : G_ ("output between %wu and %wu bytes may cause "
"result to exceed %<INT_MAX%>")); "result to exceed %<INT_MAX%>"));
res->warned = fmtwarn (loc, NULL, NULL, OPT_Wformat_length_, res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (), text,
text,
res->number_chars_min - !end, res->number_chars_min - !end,
res->number_chars_max - !end); res->number_chars_max - !end);
} }
@ -2970,14 +2990,13 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
checking built-ins. */ checking built-ins. */
if ((idx_objsize == HOST_WIDE_INT_M1U if ((idx_objsize == HOST_WIDE_INT_M1U
|| !warn_stringop_overflow)) || !warn_stringop_overflow))
warning_at (gimple_location (info.callstmt), warning_at (gimple_location (info.callstmt), info.warnopt (),
OPT_Wformat_length_,
"specified bound %wu exceeds maximum object size " "specified bound %wu exceeds maximum object size "
"%wu", "%wu",
dstsize, target_size_max () / 2); dstsize, target_size_max () / 2);
} }
else if (dstsize > target_int_max ()) 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 %>", "specified bound %wu exceeds %<INT_MAX %>",
dstsize); dstsize);
} }
@ -3028,7 +3047,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
is not constant. */ is not constant. */
location_t loc = gimple_location (info.callstmt); location_t loc = gimple_location (info.callstmt);
warning_at (EXPR_LOC_OR_LOC (dstptr, loc), warning_at (EXPR_LOC_OR_LOC (dstptr, loc),
OPT_Wformat_length_, "null destination pointer"); info.warnopt (), "null destination pointer");
return; return;
} }
@ -3044,7 +3063,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
&& (idx_objsize == HOST_WIDE_INT_M1U && (idx_objsize == HOST_WIDE_INT_M1U
|| !warn_stringop_overflow)) || !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 " "specified bound %wu exceeds the size %wu "
"of the destination object", dstsize, objsize); "of the destination object", dstsize, objsize);
} }
@ -3057,7 +3076,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
is not constant. */ is not constant. */
location_t loc = gimple_location (info.callstmt); location_t loc = gimple_location (info.callstmt);
warning_at (EXPR_LOC_OR_LOC (info.format, loc), warning_at (EXPR_LOC_OR_LOC (info.format, loc),
OPT_Wformat_length_, "null format string"); info.warnopt (), "null format string");
return; return;
} }

View File

@ -72,7 +72,7 @@ tree_int_to_gmp (tree t, mpz_t res)
static isl_id * static isl_id *
isl_id_for_pbb (scop_p s, poly_bb_p pbb) 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)); snprintf (name, sizeof (name), "S_%d", pbb_index (pbb));
return isl_id_alloc (s->isl_context, name, 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 * static isl_id *
isl_id_for_ssa_name (scop_p s, tree e) 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)); snprintf (name1, sizeof (name1), "P_%d", SSA_NAME_VERSION (e));
return isl_id_alloc (s->isl_context, name1, e); return isl_id_alloc (s->isl_context, name1, e);
} }

View 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> 2017-01-07 David Malcolm <dmalcolm@redhat.com>
PR c++/72803 PR c++/72803

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */ /* { 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: /* 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)); */ gcc_assert (line_width >= (start.column - 1 + literal_length)); */

View File

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

View File

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

View File

@ -51,7 +51,8 @@ void fuint (unsigned j, char *p)
{ {
if (j > 999) if (j > 999)
return; 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) void fint (int j, char *p)
@ -61,8 +62,7 @@ void fint (int j, char *p)
if (k > 999) if (k > 999)
return; return;
/* Range info isn't available here. */ snprintf (p, 4, "%3u", k); /* { dg-bogus "may be truncated" "signed int" { xfail *-*-* } } */
snprintf (p, 4, "%3u", k);
} }
void fulong (unsigned long j, char *p) void fulong (unsigned long j, char *p)
@ -70,8 +70,7 @@ void fulong (unsigned long j, char *p)
if (j > 999) if (j > 999)
return; return;
/* Range info isn't available here. */ snprintf (p, 4, "%3lu", j); /* { dg-bogus "may be truncated" "unsigned long" { xfail *-*-* } } */
snprintf (p, 4, "%3lu", j);
} }
void flong (long j, char *p) void flong (long j, char *p)
@ -81,8 +80,7 @@ void flong (long j, char *p)
if (k > 999) if (k > 999)
return; return;
/* Range info isn't available here. */ snprintf (p, 4, "%3lu", k); /* { dg-bogus "may be truncated" "signed long" { xfail *-*-* } } */
snprintf (p, 4, "%3lu", k);
} }
void fullong (unsigned long long j, char *p) void fullong (unsigned long long j, char *p)
@ -90,18 +88,17 @@ void fullong (unsigned long long j, char *p)
if (j > 999) if (j > 999)
return; return;
/* Range info isn't available here. */ snprintf (p, 4, "%3llu", j); /* { dg-bogus "may be truncated" "signed long" { xfail *-*-* } } */
snprintf (p, 4, "%3llu", j);
} }
void fllong (long j, char *p) void fllong (long long j, char *p)
{ {
const unsigned long long k = (unsigned long long) j; const unsigned long long k = (unsigned long long) j;
if (k > 999) if (k > 999)
return; 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" } } */ /* { dg-final { scan-tree-dump-not "abort" "optimized" } } */

View File

@ -9746,10 +9746,10 @@ get_file_function_name (const char *type)
file = LOCATION_FILE (input_location); file = LOCATION_FILE (input_location);
len = strlen (file); len = strlen (file);
q = (char *) alloca (9 + 17 + len + 1); q = (char *) alloca (9 + 19 + len + 1);
memcpy (q, file, 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)); crc32_string (0, name), get_random_seed (false));
p = q; p = q;