From patchwork Sun Jan 22 23:53:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 718310 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3v6B9f6Pbfz9t1H for ; Mon, 23 Jan 2017 10:53:58 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="OtUXdx/4"; dkim-atps=neutral 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=fZWWybHDReTzg43LuiW70Ysk0axULfIqi7q2CKgb4LGn5DgQBdpc+ hTiYZrXIxgUQNu97VRvHlx6C/ePMDxoWRhpB9i5FNWScoIvJLL3YoWWD59n2jsCs QhApJ8ef5IdwkS5JekgZ7dORz/l5Qbog5GfUbcBPCK+r0zufTqx5xo= 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=lgqBxsmCOAiCQyc9bJEgTf4zhFY=; b=OtUXdx/4ekpoteSvplB3 DhTwX6Ky7FmqYjtES8Fw1lLe+pizo7v40RwQgIuolYfK6kHxCo/Tc1XbR2gUnjz6 qarRQkbgXNqFtN87n3TJ3WZKFJ6dLHt7ubj2yys05nh7G35k42LHG6q3YLs8IvWS 9QuKzT2y5IVLGzUVuqvsQvA= Received: (qmail 103628 invoked by alias); 22 Jan 2017 23:53:14 -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 103548 invoked by uid 89); 22 Jan 2017 23:53:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 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=1046, 22187, 33047, inexact X-HELO: mail-qt0-f196.google.com Received: from mail-qt0-f196.google.com (HELO mail-qt0-f196.google.com) (209.85.216.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 22 Jan 2017 23:53:08 +0000 Received: by mail-qt0-f196.google.com with SMTP id f4so13524248qte.2 for ; Sun, 22 Jan 2017 15:53:08 -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=QYK9BwEuzLoww3aRb57kuxsINAcaM2FD5vq9zoy/HJU=; b=rW8SYmHWOcStukK5FpoS//Mbtp4t80VYsK3wPi92jUG2Z80OssSVU/0HiNlFMNrl2K 4QdOY6+wXiDZJo5dmoonDWpkM2VlSAATlMQiT6PsY2x0Tl4ONoC/eb59Sq1ADH5Ps2Xb aVqu8u8u7/RhB2pqoJGEZY58rmfYN4Undppo9uoz3dYvsNVh5N48+nd/mkNLyj+7IwHf GaFtu13lNJlrDevEcpeHOdc8SOcobEci50gHJDcdMgKFb/XKxQw01eKekpiY+hDTd2X2 OagvRnYmKC5iAf5wbgy7dwHSAysyHJUNetMRBO46+ua/M6w4GpYueAa0K/OaMdtiYNdb srFg== X-Gm-Message-State: AIkVDXJaDmnXHzfU2Lbxk6sweKwZOGphZVh0hC0hcZXGQlmy5ulWMhzdnkzwv+HYUY65pg== X-Received: by 10.237.35.179 with SMTP id j48mr20928573qtc.290.1485129187176; Sun, 22 Jan 2017 15:53:07 -0800 (PST) Received: from [192.168.0.3] (97-118-114-123.hlrn.qwest.net. [97.118.114.123]) by smtp.gmail.com with ESMTPSA id h40sm11934355qtb.6.2017.01.22.15.53.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 22 Jan 2017 15:53:06 -0800 (PST) From: Martin Sebor Subject: [PATCH 3/5] simply handling of -Wformat-overflow/truncation options (PR 78703) To: Jeff Law , Gcc Patch List Message-ID: <69b7440e-15ae-2a5a-22f3-5addde7b2bbd@gmail.com> Date: Sun, 22 Jan 2017 16:53:05 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.6.0 MIME-Version: 1.0 X-IsSubscribed: yes The attached patch is the last of the refactoring/restructuring series. It consists of the following changes: 1) Introduce a single global variable, warn_level, that the pass uses to test the level of the warning that applies to the function currently being processed (i.e., either -Wformat-overflow or -Wformat-truncation). 2) Slightly adjust the format_integer function in preparation for the upcoming substantive changes. 3) Factor code responsible for issuing per-directive warnings out of format_directive and into a function of its own, maybe_warn. This also simplifies the upcoming extensive changes in this area but more importantly, should make them easier to review by grouping warnings in the same function. 4) Enhance information printed in debugging dumps. commit d1a41d89a3b359e63937e87c619314ccd33562c5 Author: Martin Sebor Date: Fri Jan 20 17:26:56 2017 -0700 2017-01-20 Martin Sebor * gimple-ssa-sprintf.c (warn_level): New global. (format_integer): Use it here and throughout the rest of the file. Use the same switch to compute sign as base. (maybe_warn): New function. (format_directive): Factor out warnings into maybe_warn. Add debugging output. Use warn_level. (add_bytes): Use warn_level. (pass_sprintf_length::compute_format_length): Add debugging output. (try_substitute_return_value): Same. (pass_sprintf_length::handle_gimple_call): Set and use warn_level. diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index 38412b0..e3a6b3e 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -104,6 +104,12 @@ const pass_data pass_data_sprintf_length = { 0, // properties_finish }; +/* Set to the warning level for the current function which is equal + either to warn_format_trunc for bounded functions or to + warn_format_overflow otherwise. */ + +static int warn_level; + struct format_result; class pass_sprintf_length : public gimple_opt_pass @@ -137,10 +143,10 @@ public: bool pass_sprintf_length::gate (function *) { - /* Run the pass iff -Warn-format-length is specified and either - not optimizing and the pass is being invoked early, or when - optimizing and the pass is being invoked during optimization - (i.e., "late"). */ + /* Run the pass iff -Warn-format-overflow or -Warn-format-truncation + is specified and either not optimizing and the pass is being invoked + early, or when optimizing and the pass is being invoked during + optimization (i.e., "late"). */ return ((warn_format_overflow > 0 || warn_format_trunc > 0 || flag_printf_return_value) @@ -927,7 +933,37 @@ format_integer (const directive &dir, tree arg) HOST_WIDE_INT width = dir.width; HOST_WIDE_INT prec = dir.prec; - bool sign = dir.specifier == 'd' || dir.specifier == 'i'; + /* Base to format the number in. */ + int base; + + /* True when a signed conversion is preceded by a sign or space. */ + bool maybesign = false; + + /* True for signed conversions (i.e., 'd' and 'i'). */ + bool sign = false; + + switch (dir.specifier) + { + case 'd': + case 'i': + /* Space and '+' are only meaningful for signed conversions. */ + maybesign = dir.get_flag (' ') | dir.get_flag ('+'); + sign = true; + base = 10; + break; + case 'u': + base = 10; + break; + case 'o': + base = 8; + break; + case 'X': + case 'x': + base = 16; + break; + default: + gcc_unreachable (); + } /* The type of the "formal" argument expected by the directive. */ tree dirtype = NULL_TREE; @@ -998,34 +1034,6 @@ format_integer (const directive &dir, tree arg) /* When a constant argument has been provided use its value rather than type to determine the length of the output. */ - /* Base to format the number in. */ - int base; - - /* True when a signed conversion is preceded by a sign or space. */ - bool maybesign = false; - - switch (dir.specifier) - { - case 'd': - case 'i': - /* Space and '+' are only meaningful for signed conversions. */ - maybesign = dir.get_flag (' ') | dir.get_flag ('+'); - base = 10; - break; - case 'u': - base = 10; - break; - case 'o': - base = 8; - break; - case 'X': - case 'x': - base = 16; - break; - default: - gcc_unreachable (); - } - HOST_WIDE_INT len; if ((prec == HOST_WIDE_INT_MIN || prec == 0) && integer_zerop (arg)) @@ -1655,11 +1663,11 @@ format_character (const directive &dir, tree arg) to a "%lc" directive adjusted for precision but not field width. 6 is the longest UTF-8 sequence for a single wide character. */ const unsigned HOST_WIDE_INT max_bytes_for_unknown_wc - = (0 <= dir.prec ? dir.prec : warn_format_overflow > 1 ? 6 : 1); + = (0 <= dir.prec ? dir.prec : warn_level > 1 ? 6 : 1); if (dir.modifier == FMT_LEN_l) { - /* Positive if the argument is a wide NUL character? */ + /* Positive if the argument is a wide NUL character. */ int nul = (arg && TREE_CODE (arg) == INTEGER_CST ? integer_zerop (arg) : -1); @@ -1669,7 +1677,7 @@ format_character (const directive &dir, tree arg) is the smaller of either 0 (at level 1) or 1 (at level 2) and WIDTH, and the maximum is MB_CUR_MAX in the selected locale, which is unfortunately, unknown. */ - res.range.min = warn_format_overflow == 1 ? !nul : nul < 1; + res.range.min = warn_level == 1 ? !nul : nul < 1; res.range.max = max_bytes_for_unknown_wc; /* The range above is good enough to issue warnings but not for value range propagation, so clear BOUNDED. */ @@ -1746,7 +1754,7 @@ format_string (const directive &dir, tree arg) { bounded = false; - if (warn_format_overflow > 1) + if (warn_level > 1) { /* Leave the minimum number of bytes the wide string converts to equal to its length and set the maximum @@ -1860,6 +1868,145 @@ format_string (const directive &dir, tree arg) return res; } +/* At format string location describe by DIRLOC in a call described + by INFO, issue a warning for a directive DIR whose output may be + in excess of the available space AVAIL_RANGE in the destination + given the formatting result FMTRES. This function does nothing + except decide whether to issue a warning for a possible write + past the end or truncation and, if so, format the warning. + Return true if a warning has been issued. */ + +static bool +maybe_warn (substring_loc &dirloc, source_range *pargrange, + const pass_sprintf_length::call_info &info, + unsigned HOST_WIDE_INT navail, const result_range &res, + const directive &dir) +{ + bool warned = false; + + if (res.min < res.max) + { + /* The result is a range (i.e., it's inexact). */ + if (!warned) + { + if (navail < res.min) + { + /* The minimum directive output is longer than there is + room in the destination. */ + if (res.min == res.max) + { + const char* fmtstr + = (info.bounded + ? G_("%<%.*s%> directive output truncated writing " + "%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, info.warnopt (), + fmtstr, + (int)dir.len, dir.beg, res.min, + navail); + } + else if (res.max < HOST_WIDE_INT_MAX) + { + const char* fmtstr + = (info.bounded + ? G_("%<%.*s%> directive output truncated writing " + "between %wu and %wu bytes into a region of " + "size %wu") + : G_("%<%.*s%> directive writing between %wu and " + "%wu bytes into a region of size %wu")); + warned = fmtwarn (dirloc, pargrange, NULL, + info.warnopt (), fmtstr, + (int)dir.len, dir.beg, + res.min, res.max, navail); + } + else + { + const char* fmtstr + = (info.bounded + ? G_("%<%.*s%> directive output truncated writing " + "%wu or more bytes into a region of size %wu") + : G_("%<%.*s%> directive writing %wu or more bytes " + "into a region of size %wu")); + warned = fmtwarn (dirloc, pargrange, NULL, + info.warnopt (), fmtstr, + (int)dir.len, dir.beg, + res.min, navail); + } + } + else if (navail < res.max + && (dir.specifier != 's' + || res.max < HOST_WIDE_INT_MAX) + && ((info.bounded + && (!info.retval_used () + || warn_level > 1)) + || (!info.bounded + && (dir.specifier == 's' + || warn_level > 1)))) + { + /* The maximum directive output is longer than there is + room in the destination and the output length is either + explicitly constrained by the precision (for strings) + or the warning level is greater than 1. */ + if (res.max >= HOST_WIDE_INT_MAX) + { + const char* fmtstr + = (info.bounded + ? G_("%<%.*s%> directive output may be truncated " + "writing %wu or more bytes into a region " + "of size %wu") + : G_("%<%.*s%> directive writing %wu or more bytes " + "into a region of size %wu")); + warned = fmtwarn (dirloc, pargrange, NULL, + info.warnopt (), fmtstr, + (int)dir.len, dir.beg, + res.min, navail); + } + else + { + const char* fmtstr + = (info.bounded + ? G_("%<%.*s%> directive output may be truncated " + "writing between %wu and %wu bytes into a region " + "of size %wu") + : G_("%<%.*s%> directive writing between %wu and %wu " + "bytes into a region of size %wu")); + warned = fmtwarn (dirloc, pargrange, NULL, + info.warnopt (), fmtstr, + (int)dir.len, dir.beg, + res.min, res.max, + navail); + } + } + } + } + else + { + if (!warned && res.min > 0 && navail < res.min) + { + const char* fmtstr + = (info.bounded + ? (1 < res.min + ? G_("%<%.*s%> directive output truncated while writing " + "%wu bytes into a region of size %wu") + : G_("%<%.*s%> directive output truncated while writing " + "%wu byte into a region of size %wu")) + : (1 < res.min + ? G_("%<%.*s%> directive writing %wu bytes " + "into a region of size %wu") + : G_("%<%.*s%> directive writing %wu byte " + "into a region of size %wu"))); + + warned = fmtwarn (dirloc, pargrange, NULL, + info.warnopt (), fmtstr, + (int)dir.len, dir.beg, res.min, + navail); + } + } + + return warned; +} + /* Compute the length of the output resulting from the conversion specification DIR with the argument ARG in a call described by INFO and update the overall result of the call in *RES. The format directive @@ -1960,109 +2107,19 @@ format_directive (const pass_sprintf_length::call_info &info, return false; } - bool warned = res->warned; - /* Compute the number of available bytes in the destination. There must always be at least one byte of space for the terminating NUL that's appended after the format string has been processed. */ unsigned HOST_WIDE_INT navail = min_bytes_remaining (info.objsize, *res); + bool warned = res->warned; + + if (!warned) + warned = maybe_warn (dirloc, pargrange, info, navail, + fmtres.range, dir); + if (fmtres.range.min < fmtres.range.max) { - /* The result is a range (i.e., it's inexact). */ - if (!warned) - { - if (navail < fmtres.range.min) - { - /* The minimum directive output is longer than there is - room in the destination. */ - if (fmtres.range.min == fmtres.range.max) - { - const char* fmtstr - = (info.bounded - ? G_("%<%.*s%> directive output truncated writing " - "%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, info.warnopt (), - fmtstr, - (int)cvtlen, cvtbeg, fmtres.range.min, - navail); - } - else if (fmtres.range.max < HOST_WIDE_INT_MAX) - { - const char* fmtstr - = (info.bounded - ? G_("%<%.*s%> directive output truncated writing " - "between %wu and %wu bytes into a region of " - "size %wu") - : G_("%<%.*s%> directive writing between %wu and " - "%wu bytes into a region of size %wu")); - warned = fmtwarn (dirloc, pargrange, NULL, - info.warnopt (), fmtstr, - (int)cvtlen, cvtbeg, - fmtres.range.min, fmtres.range.max, navail); - } - else - { - const char* fmtstr - = (info.bounded - ? G_("%<%.*s%> directive output truncated writing " - "%wu or more bytes into a region of size %wu") - : G_("%<%.*s%> directive writing %wu or more bytes " - "into a region of size %wu")); - warned = fmtwarn (dirloc, pargrange, NULL, - info.warnopt (), fmtstr, - (int)cvtlen, cvtbeg, - fmtres.range.min, navail); - } - } - else if (navail < fmtres.range.max - && (dir.specifier != 's' - || fmtres.range.max < HOST_WIDE_INT_MAX) - && ((info.bounded - && (!info.retval_used () - || warn_format_trunc > 1)) - || (!info.bounded - && (dir.specifier == 's' - || warn_format_overflow > 1)))) - { - /* The maximum directive output is longer than there is - room in the destination and the output length is either - explicitly constrained by the precision (for strings) - or the warning level is greater than 1. */ - if (fmtres.range.max >= HOST_WIDE_INT_MAX) - { - const char* fmtstr - = (info.bounded - ? G_("%<%.*s%> directive output may be truncated " - "writing %wu or more bytes into a region " - "of size %wu") - : G_("%<%.*s%> directive writing %wu or more bytes " - "into a region of size %wu")); - warned = fmtwarn (dirloc, pargrange, NULL, - info.warnopt (), fmtstr, - (int)cvtlen, cvtbeg, - fmtres.range.min, navail); - } - else - { - const char* fmtstr - = (info.bounded - ? G_("%<%.*s%> directive output may be truncated " - "writing between %wu and %wu bytes into a region " - "of size %wu") - : G_("%<%.*s%> directive writing between %wu and %wu " - "bytes into a region of size %wu")); - warned = fmtwarn (dirloc, pargrange, NULL, - info.warnopt (), fmtstr, - (int)cvtlen, cvtbeg, - fmtres.range.min, fmtres.range.max, - navail); - } - } - } - /* Disable exact length checking but adjust the minimum and maximum. */ res->number_chars = HOST_WIDE_INT_M1U; if (res->number_chars_max < HOST_WIDE_INT_MAX @@ -2072,29 +2129,7 @@ format_directive (const pass_sprintf_length::call_info &info, res->number_chars_min += fmtres.range.min; } else - { - if (!warned && fmtres.range.min > 0 && navail < fmtres.range.min) - { - const char* fmtstr - = (info.bounded - ? (1 < fmtres.range.min - ? G_("%<%.*s%> directive output truncated while writing " - "%wu bytes into a region of size %wu") - : G_("%<%.*s%> directive output truncated while writing " - "%wu byte into a region of size %wu")) - : (1 < fmtres.range.min - ? G_("%<%.*s%> directive writing %wu bytes " - "into a region of size %wu") - : G_("%<%.*s%> directive writing %wu byte " - "into a region of size %wu"))); - - warned = fmtwarn (dirloc, pargrange, NULL, - info.warnopt (), fmtstr, - (int)cvtlen, cvtbeg, fmtres.range.min, - navail); - } *res += fmtres.range.min; - } /* Has the minimum directive output length exceeded the maximum of 4095 bytes required to be supported? */ @@ -2102,7 +2137,7 @@ format_directive (const pass_sprintf_length::call_info &info, if (!minunder4k || fmtres.range.max > 4095) res->under4k = false; - if (!warned && warn_format_overflow > 1 + if (!warned && warn_level > 1 && (!minunder4k || fmtres.range.max > 4095)) { /* The directive output may be longer than the maximum required @@ -2139,7 +2174,7 @@ format_directive (const pass_sprintf_length::call_info &info, if (!warned && (exceedmin - || (warn_format_overflow > 1 + || (warn_level > 1 && res->number_chars_max > target_int_max ()))) { /* The directive output causes the total length of output @@ -2179,6 +2214,18 @@ format_directive (const pass_sprintf_length::call_info &info, } res->warned |= warned; + + if (dump_file && *dir.beg) + { + fprintf (dump_file, " Result: %lli, %lli " + "(%lli, %lli, %lli)\n", + (long long)fmtres.range.min, + (long long)fmtres.range.max, + (long long)res->number_chars, + (long long)res->number_chars_min, + (long long)res->number_chars_max); + } + return true; } @@ -2218,7 +2265,7 @@ add_bytes (const pass_sprintf_length::call_info &info, are bounded by the arrays they are known to refer to. */ if (!res->warned && (avail_range.max < nbytes - || ((res->knownrange || warn_format_overflow > 1) + || ((res->knownrange || warn_level > 1) && avail_range.min < nbytes))) { /* Set NAVAIL to the number of available bytes used to decide @@ -2226,7 +2273,7 @@ add_bytes (const pass_sprintf_length::call_info &info, warning will depend on AVAIL_RANGE. */ unsigned HOST_WIDE_INT navail = avail_range.max; if (nbytes <= navail && avail_range.min < HOST_WIDE_INT_MAX - && (res->knownrange || warn_format_overflow > 1)) + && (res->knownrange || warn_level > 1)) navail = avail_range.min; /* Compute the offset of the first format character that is beyond @@ -2271,7 +2318,7 @@ add_bytes (const pass_sprintf_length::call_info &info, if (!info.bounded || !boundrange || !info.retval_used () - || warn_format_trunc > 1) + || warn_level > 1) res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (), text); } else @@ -2293,7 +2340,7 @@ add_bytes (const pass_sprintf_length::call_info &info, if (!info.bounded || !boundrange || !info.retval_used () - || warn_format_trunc > 1) + || warn_level > 1) res->warned = fmtwarn (loc, NULL, NULL, info.warnopt (), text, info.fmtstr[off], off); } @@ -2335,7 +2382,7 @@ add_bytes (const pass_sprintf_length::call_info &info, if (!res->warned && (exceedmin - || (warn_format_overflow > 1 + || (warn_level > 1 && (res->number_chars_max - !end) > target_int_max ()))) { /* The function's output exceeds INT_MAX bytes. */ @@ -2345,7 +2392,7 @@ add_bytes (const pass_sprintf_length::call_info &info, warning will depend on AVAIL_RANGE. */ unsigned HOST_WIDE_INT navail = avail_range.max; if (nbytes <= navail && avail_range.min < HOST_WIDE_INT_MAX - && (res->bounded || warn_format_overflow > 1)) + && (res->bounded || warn_level > 1)) navail = avail_range.min; /* Compute the offset of the first format character that is beyond @@ -2752,6 +2799,17 @@ bool pass_sprintf_length::compute_format_length (call_info &info, format_result *res) { + if (dump_file) + { + location_t callloc = gimple_location (info.callstmt); + fprintf (dump_file, "%s:%i: ", + LOCATION_FILE (callloc), LOCATION_LINE (callloc)); + print_generic_expr (dump_file, info.func, dump_flags); + + fprintf (dump_file, ": objsize = %llu, fmtstr = \"%s\"\n", + (unsigned long long)info.objsize, info.fmtstr); + } + /* Reset exact, minimum, and maximum character counters. */ res->number_chars = res->number_chars_min = res->number_chars_max = 0; @@ -2811,14 +2869,15 @@ pass_sprintf_length::compute_format_length (call_info &info, static unsigned HOST_WIDE_INT get_destination_size (tree dest) { + /* Initialize object size info before trying to compute it. */ + init_object_sizes (); + /* Use __builtin_object_size to determine the size of the destination object. When optimizing, determine the smallest object (such as a member array as opposed to the whole enclosing object), otherwise use type-zero object size to determine the size of the enclosing object (the function fails without optimization in this type). */ - init_object_sizes (); - int ost = optimize > 0; unsigned HOST_WIDE_INT size; if (compute_builtin_object_size (dest, ost, &size)) @@ -2966,7 +3025,10 @@ try_substitute_return_value (gimple_stmt_iterator *gsi, } } - return false; + if (dump_file) + fputc ('\n', dump_file); + + return removed; } /* Determine if a GIMPLE CALL is to one of the sprintf-like built-in @@ -3074,6 +3136,9 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi) return false; } + /* Set the global warning level for this function. */ + warn_level = info.bounded ? warn_format_trunc : warn_format_overflow; + /* The first argument is a pointer to the destination. */ tree dstptr = gimple_call_arg (info.callstmt, 0); @@ -3127,7 +3192,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi) if (range_type == VR_RANGE) { dstsize - = (warn_format_overflow < 2 + = (warn_level < 2 ? wi::fits_uhwi_p (max) ? max.to_uhwi () : max.to_shwi () : wi::fits_uhwi_p (min) ? min.to_uhwi () : min.to_shwi ()); } @@ -3213,6 +3278,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi) && flag_printf_return_value && (!flag_rounding_math || !res.floating)) return try_substitute_return_value (gsi, info, res); + return false; } @@ -3238,6 +3304,7 @@ pass_sprintf_length::execute (function *fun) } } + /* Clean up object size info. */ fini_object_sizes (); return 0;