From patchwork Wed Jan 4 00:04:48 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 89750 Delivered-To: patch@linaro.org Received: by 10.140.20.101 with SMTP id 92csp8252052qgi; Tue, 3 Jan 2017 16:05:13 -0800 (PST) X-Received: by 10.84.238.15 with SMTP id u15mr48269281plk.8.1483488313514; Tue, 03 Jan 2017 16:05:13 -0800 (PST) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id 94si42518112plv.8.2017.01.03.16.05.13 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Jan 2017 16:05:13 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-445286-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-445286-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-445286-patch=linaro.org@gcc.gnu.org; dmarc=fail (p=NONE dis=NONE) header.from=gmail.com DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; q=dns; s= default; b=VDN//NNpaezJrHXM2x0IIR/6eW2jk3d1cUF6qvITmSj+D72/Y+UzQ 6AxDgUNRD6qsJ/CO4STELmHmUzidpIADfdE27gBdgjcig/PeWWDVzDQkkvwiMBQD xNm5fgmdv/U5rA2awcheZTlzush1tNfPSedpg9HfzbO3KqZD8XBqws= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; s= default; bh=+/IoC8ZHESuy0xSTj28W2I3V588=; b=apUdd4/wIE+NFBTJOtMM ZMDTCpcLqQwW+uhiLMp6ZtFltZB0UOG9O/6DLKqjjB3t/5qi+4wZMuRZskz99uac bchheQF8nu66oK6ku8PCUOUaV3KvukPtxdxCgqtJDTyyDnUUhRs6tpepiswO/rqz QyZ70kQ18n8psBQ3a55mXEM= Received: (qmail 43720 invoked by alias); 4 Jan 2017 00:04:57 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 43706 invoked by uid 89); 4 Jan 2017 00:04:56 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=@gcctabopt, gcctabopt, 21017, yielding X-HELO: mail-qt0-f182.google.com Received: from mail-qt0-f182.google.com (HELO mail-qt0-f182.google.com) (209.85.216.182) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 04 Jan 2017 00:04:52 +0000 Received: by mail-qt0-f182.google.com with SMTP id k15so238684427qtg.3 for ; Tue, 03 Jan 2017 16:04:52 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:subject:to:message-id:date:user-agent :mime-version; bh=+NGciQLvgzbs8kHjopIj3bQT20bp6Asg9j1mf/FEv6M=; b=Xm57fpV0DuM6P014PNQYCBQcbbc+6e5YEkx8VYNso9QTDT3EARw8URLLkM0VM8o98q TjTzZaXj6Q04AmuC5m9VzIVLNjeU3OwN7+CrlkFEy6MrvuBDOU/9rgyjcc18ZGh+4WNt 4d1pRXrG6o5NmkfIrLbAUtuKRzOpM5M9AEswAEh2lxL+CJoyMMzhqYSmySKeEt79vIM6 mzEa8a7gvG0HYLqigdRYPDpx4tRqLmOkkqj4DLvIY2rQglUFyILXv1aZy0ReT4hAIdMP EUQ1Gfdz6mmupKetV+gwK2CXkXy2dhJDD2GUPnD/Rm5obb2a+UMi/ZXikj7h/9afKN30 zc2Q== X-Gm-Message-State: AIkVDXJawKdqud2oJVUDsNkIy3J0OwKMkwFVnpyg8xnSXPK3Y0hmmj9T1/d7D9ClmgD1Ww== X-Received: by 10.237.32.68 with SMTP id 62mr56922510qta.231.1483488290694; Tue, 03 Jan 2017 16:04:50 -0800 (PST) Received: from [192.168.0.26] (71-212-249-238.hlrn.qwest.net. [71.212.249.238]) by smtp.gmail.com with ESMTPSA id a81sm44746942qkg.28.2017.01.03.16.04.49 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Jan 2017 16:04:50 -0800 (PST) From: Martin Sebor Subject: [PATCH] move snprintf truncation warnings under own option () To: Gcc Patch List Message-ID: <81014ef4-2803-82b7-d24e-d32cfb69cad6@gmail.com> Date: Tue, 3 Jan 2017 17:04:48 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 MIME-Version: 1.0 X-IsSubscribed: yes The -Wformat-length option warns about both overflow and truncation. I had initially debated introducing two options, one for each of the two kinds of problems, but decided to go with just one and consider breaking it up based on feedback. I feel that there has now been sufficient feedback (e.g., bugs 77708 and 78913) to justify breaking up the checkers and providing a new option to control truncation independently. The attached patch adds a new option, -Wformat-truncation=level that accomplishes this. At level 1 the new option only warns on certain truncation, or on likely truncation in snprintf calls whose return value is unused (using the return value suppresses the warning in these cases). This change eliminates the -Wformat-length warnings from a build of the Linux kernel, replacing their 43 instances with 32 of the -Wformat-truncation warning. With one exception, they're all for snprintf calls whose return values is unused (and thus possible sources of bugs). If/when this patch is approved I'd like to rename -Wformat-length to -Wformat-overflow to make the option's refined purpose clear, and for consistency with the -Wstringop-overflow option. Martin PR tree-optimization/78913 - Probably misleading error reported by -Wformat-length PR middle-end/77708 - -Wformat-length %s warns for snprintf gcc/c-family/ChangeLog: PR tree-optimization/78913 PR middle-end/77708 * c.opt (-Wformat-truncation): New option. gcc/testsuite/ChangeLog: PR tree-optimization/78913 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/ChangeLog: PR tree-optimization/78913 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. diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 3c06aec..849634c 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 a8f8efe..2ae265a 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 @@ -8413,8 +8440,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/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index 907a064..7b3e5a1 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -712,6 +712,18 @@ struct pass_sprintf_length::call_info buffer as a request to compute the size of output without actually writing any. */ 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. */ @@ -1925,8 +1937,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); @@ -1961,8 +1972,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); } @@ -1976,7 +1987,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); } @@ -1989,16 +2000,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 @@ -2013,7 +2028,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); } @@ -2027,7 +2042,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); @@ -2061,7 +2076,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); } @@ -2086,7 +2101,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); @@ -2100,7 +2115,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); } @@ -2118,8 +2133,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); @@ -2132,7 +2146,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); } @@ -2240,7 +2254,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 { @@ -2258,8 +2276,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); } } @@ -2326,8 +2348,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); @@ -2339,8 +2360,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); } @@ -2930,14 +2950,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); } @@ -2988,7 +3007,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; } @@ -3004,7 +3023,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); } @@ -3017,7 +3036,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/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 0000000..cc226ca --- /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 0000000..93c9f1b --- /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 121ed4e..93c53a4 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" } } */