From patchwork Tue Feb 5 03:58:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 1036419 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-495281-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="kwBA781G"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FxQIIVrx"; dkim-atps=neutral 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 43trRG5z38z9sNG for ; Tue, 5 Feb 2019 14:58:47 +1100 (AEDT) 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=PADWDUrqhSI5zMhQ2xcNgC6fca831vEfnTx6npmC2joPi35ZBcr8q I/w/v7R+3eXy9ERyHfL+Qru/jaNWyuQrrTKBIIV9aOTG8y/wZslRRbGKevUvPm88 gLxwtB1uCrK4szEY7lblR9ocYzXvykWUjjTiI3M/Fr5S/OKxq+WgUA= 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=1WXbhTmiaQAlKwP+DJjyKvoSfD8=; b=kwBA781GwpsjEzTYsgdI ktEPXsUYqd4nCj7vY+0gVb7CrDHBc/98RDoh7eygrlsEbYFpLaGqXXxBtpmYvCAx L9RlQlFNcVcmMsrXAI2uFx8e+LMET1bS9DuFOWeaUutMHt0e3L/7A/ElffSvhWf7 Habmjn4a78e4a25xb65SWnc= Received: (qmail 21632 invoked by alias); 5 Feb 2019 03:58:39 -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 21615 invoked by uid 89); 5 Feb 2019 03:58:39 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=Exercise, warned X-HELO: mail-qk1-f179.google.com Received: from mail-qk1-f179.google.com (HELO mail-qk1-f179.google.com) (209.85.222.179) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 05 Feb 2019 03:58:35 +0000 Received: by mail-qk1-f179.google.com with SMTP id m9so1333947qkl.4 for ; Mon, 04 Feb 2019 19:58:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:subject:to:message-id:date:user-agent:mime-version :content-language; bh=Wi3/WoKOCQ69OSK5Tvply4spAAbxBhjhnuvAQSphT+o=; b=FxQIIVrxmKIJcJ1pBKP7lOw7OjDJ4QkliHrczCSboqMHrnfnBwDh2PE10IGGcl8owv 64XtyFURU+KAbk+kKPVwtRfPwPU8HRwJD5OJHjco2A2lPHyrI8KLI3/t9Q8fDJ8qGslc aULGH/2pIKpcsLkSxDaNfqJgK1lVNMs9HT6SvLMRJ/490gGPgtGtWl4rM+9QyaLT6FwQ 4ZrwtIBI3Cdrbl4+5SvwwdG2PI2N9g7MG0Txs+92i+FDEYqd+PVxG3xV60laNE9YgRQr 7fmFztyfQqyF+QiXqOZn47xZRRwRU9XQye5L7E2pAY+P7Kv0oEWBuRCTMXHeU5mpJfl1 vbvw== Received: from [192.168.0.106] (75-166-110-80.hlrn.qwest.net. [75.166.110.80]) by smtp.gmail.com with ESMTPSA id e26sm13556067qtg.69.2019.02.04.19.58.31 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 04 Feb 2019 19:58:32 -0800 (PST) From: Martin Sebor Subject: [PATCH] avoid 4095/INT_MAX warning for fprintf (PR 88993) To: "gcc-patches@gcc.gnu.org" Message-ID: <64289290-761d-1162-659d-f69112aed453@gmail.com> Date: Mon, 4 Feb 2019 20:58:30 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.1 MIME-Version: 1.0 X-IsSubscribed: yes The attached patch relaxes -Wformat-overflow=2 to avoid warning about individual directives that might (but need not) exceed the 4095 byte limit, and about the total function output that likewise might (but need not) exceed the INT_MAX limit. The bug report actually requests that instead of the standard minimum of 4095 bytes, GCC consider real libc limits, but trying to figure out what these real limits might be (they're not documented anywhere, AFAIK) and hardcoding them into GCC doesn't seem like a good solution. Instead, the patch only does little more than the bare minimum to suppress these pedantic warnings, and it only does that for the "may exceed" cases and not for those where the size of output definitely exceeds either limit. Using the formatted functions to write such large amounts of data seems more likely to be a bug than intentional, and at level 2 issuing the warning seems appropriate unless the return value of the function is tested. When it is, even tough exceeding these limits is strictly undefined, it seems reasonable to assume that a quality libc implementation will detect it and return an error (as required by POSIX). So with the patch, the only way to get this warning is for calls to sprintf or to unchecked snprintf. Martin PR c/88993 - GCC 9 -Wformat-overflow=2 should reflect real libc limits gcc/ChangeLog: PR c/88993 * gimple-ssa-sprintf.c (sprintf_dom_walker::call_info::is_file_func): New helper. (sprintf_dom_walker::call_info::is_string_func): New helper. (format_directive): Only issue "may exceed" 4095/INT_MAX warnings for formatted string functions. (sprintf_dom_walker::handle_gimple_call): Fix a typo in a comment. gcc/testsuite/ChangeLog: PR c/88993 * gcc.dg/tree-ssa/builtin-fprintf-warn-2.c: New test. * gcc.dg/tree-ssa/builtin-printf-warn-2.c: New test. * testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c: Adjust. Index: gimple-ssa-sprintf.c =================================================================== --- gimple-ssa-sprintf.c (revision 268525) +++ gimple-ssa-sprintf.c (working copy) @@ -943,6 +943,29 @@ struct sprintf_dom_walker::call_info { return bounded ? OPT_Wformat_truncation_ : OPT_Wformat_overflow_; } + + /* Return true for calls to file formatted functions. */ + bool is_file_func () const + { + return (fncode == BUILT_IN_FPRINTF + || fncode == BUILT_IN_FPRINTF_CHK + || fncode == BUILT_IN_FPRINTF_UNLOCKED + || fncode == BUILT_IN_VFPRINTF + || fncode == BUILT_IN_VFPRINTF_CHK); + } + + /* Return true for calls to string formatted fncodetions. */ + bool is_string_func () const + { + return (fncode == BUILT_IN_SPRINTF + || fncode == BUILT_IN_SPRINTF_CHK + || fncode == BUILT_IN_SNPRINTF + || fncode == BUILT_IN_SNPRINTF_CHK + || fncode == BUILT_IN_VSPRINTF + || fncode == BUILT_IN_VSPRINTF_CHK + || fncode == BUILT_IN_VSNPRINTF + || fncode == BUILT_IN_VSNPRINTF_CHK); + } }; /* Return the result of formatting a no-op directive (such as '%n'). */ @@ -2847,7 +2870,9 @@ format_directive (const sprintf_dom_walker::call_i of C11. Warn on this only at level 2 but remember this and prevent folding the return value when done. This allows for the possibility of the actual libc call failing due to ENOMEM - (like Glibc does under some conditions). */ + (like Glibc does with very large precision or width). + Issue the "may exceed" warning only for string functions and + not for fprintf or printf. */ if (fmtres.range.min == fmtres.range.max) warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), @@ -2855,17 +2880,21 @@ format_directive (const sprintf_dom_walker::call_i "minimum required size of 4095", dirlen, target_to_host (hostdir, sizeof hostdir, dir.beg), fmtres.range.min); - else + else if (!minunder4k) warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - minunder4k - ? G_("%<%.*s%> directive output between %wu and %wu " - "bytes may exceed minimum required size of " - "4095") - : G_("%<%.*s%> directive output between %wu and %wu " - "bytes exceeds minimum required size of 4095"), + "%<%.*s%> directive output between %wu and %wu " + "bytes exceeds minimum required size of 4095", dirlen, target_to_host (hostdir, sizeof hostdir, dir.beg), fmtres.range.min, fmtres.range.max); + else if (!info.retval_used () && info.is_string_func ()) + warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), + "%<%.*s%> directive output between %wu and %wu " + "bytes may exceed minimum required size of " + "4095", + dirlen, + target_to_host (hostdir, sizeof hostdir, dir.beg), + fmtres.range.min, fmtres.range.max); } /* Has the likely and maximum directive output exceeded INT_MAX? */ @@ -2885,26 +2914,32 @@ format_directive (const sprintf_dom_walker::call_i && maxximax && fmtres.range.max < HOST_WIDE_INT_MAX))) { - /* The directive output causes the total length of output - to exceed INT_MAX bytes. */ + /* The directive output or either causes or may cause the total + length of output to exceed INT_MAX bytes. */ - if (fmtres.range.min == fmtres.range.max) + if (likelyximax && fmtres.range.min == fmtres.range.max) warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), "%<%.*s%> directive output of %wu bytes causes " "result to exceed %", dirlen, target_to_host (hostdir, sizeof hostdir, dir.beg), fmtres.range.min); - else + else if (fmtres.range.min > target_int_max ()) warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - fmtres.range.min > target_int_max () - ? G_("%<%.*s%> directive output between %wu and " - "%wu bytes causes result to exceed " - "%") - : G_("%<%.*s%> directive output between %wu and " - "%wu bytes may cause result to exceed " - "%"), dirlen, + "%<%.*s%> directive output between %wu and " + "%wu bytes causes result to exceed " + "%", dirlen, target_to_host (hostdir, sizeof hostdir, dir.beg), fmtres.range.min, fmtres.range.max); + else if ((!info.retval_used () || !info.bounded) + && (info.is_string_func ())) + /* Warn for calls to string functions that either aren't bounded + (sprintf) or whose return value isn't used. */ + warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), + "%<%.*s%> directive output between %wu and " + "%wu bytes may cause result to exceed " + "%", dirlen, + target_to_host (hostdir, sizeof hostdir, dir.beg), + fmtres.range.min, fmtres.range.max); } if (!warned && fmtres.nonstr) @@ -3842,7 +3877,7 @@ sprintf_dom_walker::handle_gimple_call (gimple_stm case BUILT_IN_PRINTF_CHK: // Signature: - // __builtin_printf_chk (it, format, ...) + // __builtin_printf_chk (ost, format, ...) idx_format = 1; info.argidx = 2; idx_dstptr = -1; Index: testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c =================================================================== --- testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c (nonexistent) +++ testsuite/gcc.dg/tree-ssa/builtin-fprintf-warn-2.c (working copy) @@ -0,0 +1,159 @@ +/* PR middle-end/88993 - GCC 9 -Wformat-overflow=2 should reflect real + libc limits + Verify that -Wformat-overflow=2 "may exceed" warnings are not issued + for printf family of functions. + { dg-do compile } + { dg-options "-O -Wformat -Wformat-overflow=2 -ftrack-macro-expansion=0" } + { dg-require-effective-target int32plus } */ + +#define INT_MAX __INT_MAX__ + +typedef __SIZE_TYPE__ size_t; + +#if !__cplusplus +typedef __WCHAR_TYPE__ wchar_t; +#endif + +typedef struct FILE FILE; + +FILE *fp; + +#define T(...) __builtin_fprintf (__VA_ARGS__) + +/* Exercise the "%c" directive with constant arguments. */ + +void test_printf_c_const (int width) +{ + /* Verify that a "may exceed" warning is only issued when the output + is definitely exceeded but not when exceeding it is possible but + not inevitable. */ + T (fp, "%*c", INT_MAX, '1'); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T (fp, "%*c", 4096, '1'); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T (fp, "X%*c", 4095, '1'); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T (fp, "%*c", width, '1'); + T (fp, "%*cX", width, '1'); + T (fp, "%*c%*c", width, '1', width, '2'); + T (fp, "X%*cY%*cZ", width, '1', width, '2'); + + if (width < 4096) + width = 4096; + + T (fp, "%*c", width, '1'); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + + +/* Exercise the "%s" directive with constant arguments. */ + +void test_printf_s_const (int width) +{ + const char *s = ""; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T (fp, "%*s", INT_MAX, s); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T (fp, "%*s", 4096, s); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T (fp, "X%*s", 4095, s); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T (fp, "%*s", width, s); + T (fp, "%*sX", width, s); + T (fp, "%*s%*s", width, s, width, s); + T (fp, "X%*sY%*sZ", width, s, width, s); + + if (width < 4096) + width = 4096; + + T (fp, "%*s", width, s); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + +/* Exercise the "%ls" directive with constant arguments. */ + +void test_printf_ls_const (int width) +{ + const wchar_t *ls = L""; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T (fp, "%*ls", INT_MAX, ls); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T (fp, "%*ls", 4096, ls); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T (fp, "X%*ls", 4095, ls); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T (fp, "%*ls", width, ls); + T (fp, "%*lsX", width, ls); + T (fp, "%*ls%*ls", width, ls, width, ls); + T (fp, "X%*lsY%*lsZ", width, ls, width, ls); + + if (width < 4096) + width = 4096; + + T (fp, "%*ls", width, ls); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + + +/* Also exercise fprintf_chk. */ + +#undef T +#define T(...) __builtin___fprintf_chk (__VA_ARGS__) + +void test_printf_chk_s_const (int width) +{ + const char *s = "0123456789"; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T (fp, 0, "%*s", INT_MAX, s); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T (fp, 0, "%*s", 4096, s); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T (fp, 0, "X%*s", 4095, s); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T (fp, 0, "%*s", width, s); + T (fp, 0, "%*sX", width, s); + T (fp, 0, "%*s%*s", width, s, width, s); + T (fp, 0, "X%*sY%*sZ", width, s, width, s); + + if (width < 4096) + width = 4096; + + T (fp, 0, "%*s", width, s); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + + +/* And finally exercise fprintf_unlocked. */ + +#undef T +#define T(...) __builtin_fprintf_unlocked (__VA_ARGS__) + +void test_printf_unlocked_s_const (int width) +{ + const char *s = "0123456789"; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T (fp, "%*s", INT_MAX, s); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T (fp, "%*s", 4096, s); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T (fp, "X%*s", 4095, s); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T (fp, "%*s", width, s); + T (fp, "%*sX", width, s); + T (fp, "%*s%*s", width, s, width, s); + T (fp, "X%*sY%*sZ", width, s, width, s); + + if (width < 4096) + width = 4096; + + T (fp, "%*s", width, s); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} Index: testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c =================================================================== --- testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c (nonexistent) +++ testsuite/gcc.dg/tree-ssa/builtin-printf-warn-2.c (working copy) @@ -0,0 +1,170 @@ +/* PR middle-end/88993 - GCC 9 -Wformat-overflow=2 should reflect real + libc limits + Verify that -Wformat-overflow=2 "may exceed" warnings are not issued + for printf family of functions. + { dg-do compile } + { dg-options "-O -Wformat -Wformat-overflow=2 -ftrack-macro-expansion=0" } + { dg-require-effective-target int32plus } */ + +/* When debugging, define LINE to the line number of the test case to exercise + and avoid exercising any of the others. */ +#ifndef LINE +# define LINE 0 +#endif + +#define INT_MAX __INT_MAX__ + +typedef __SIZE_TYPE__ size_t; + +#if !__cplusplus +typedef __WCHAR_TYPE__ wchar_t; +#endif + +int dummy_printf (const char*, ...); + + +/* Helper to expand function to either __builtin_f or dummy_f to + make debugging GCC easy. */ +#define T(...) \ + (((!LINE || LINE == __LINE__) \ + ? __builtin_printf : dummy_printf) (__VA_ARGS__)) + +/* Exercise the "%c" directive with constant arguments. */ + +void test_printf_c_const (int width) +{ + /* Verify that a "may exceed" warning is only issued when the output + is definitely exceeded but not when exceeding it is possible but + not inevitable. */ + T ("%*c", INT_MAX, '1'); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T ("%*c", 4096, '1'); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T ("X%*c", 4095, '1'); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T ("%*c", width, '1'); + T ("%*cX", width, '1'); + T ("%*c%*c", width, '1', width, '2'); + T ("X%*cY%*cZ", width, '1', width, '2'); + + if (width < 4096) + width = 4096; + + T ("%*c", width, '1'); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + + +/* Exercise the "%s" directive with constant arguments. */ + +void test_printf_s_const (int width) +{ + const char *s = ""; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T ("%*s", INT_MAX, s); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T ("%*s", 4096, s); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T ("X%*s", 4095, s); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T ("%*s", width, s); + T ("%*sX", width, s); + T ("%*s%*s", width, s, width, s); + T ("X%*sY%*sZ", width, s, width, s); + + if (width < 4096) + width = 4096; + + T ("%*s", width, s); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + +/* Exercise the "%ls" directive with constant arguments. */ + +void test_printf_ls_const (int width) +{ + const wchar_t *ls = L""; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T ("%*ls", INT_MAX, ls); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T ("%*ls", 4096, ls); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T ("X%*ls", 4095, ls); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T ("%*ls", width, ls); + T ("%*lsX", width, ls); + T ("%*ls%*ls", width, ls, width, ls); + T ("X%*lsY%*lsZ", width, ls, width, ls); + + if (width < 4096) + width = 4096; + + T ("%*ls", width, ls); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + + +/* Also exercise printf_chk. */ + +#undef T +#define T(...) __builtin___printf_chk (__VA_ARGS__) + +void test_printf_chk_s_const (int width) +{ + const char *s = "0123456789"; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T (0, "%*s", INT_MAX, s); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T (0, "%*s", 4096, s); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T (0, "X%*s", 4095, s); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T (0, "%*s", width, s); + T (0, "%*sX", width, s); + T (0, "%*s%*s", width, s, width, s); + T (0, "X%*sY%*sZ", width, s, width, s); + + if (width < 4096) + width = 4096; + + T (0, "%*s", width, s); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} + + +/* And finally exercise printf_unlocked. */ + +#undef T +#define T(...) \ + (((!LINE || LINE == __LINE__) \ + ? __builtin_printf_unlocked : dummy_printf) (__VA_ARGS__)) + +void test_printf_unlocked_s_const (int width) +{ + const char *s = "0123456789"; + + /* Verify that output in excess of INT_MAX bytes is diagnosed even + when the size of the destination object is unknown. */ + T ("%*s", INT_MAX, s); /* { dg-warning "directive output of \[0-9\]+ bytes exceeds minimum required size of 4095" } */ + T ("%*s", 4096, s); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ + T ("X%*s", 4095, s); + + if (width > INT_MAX - 1) + width = INT_MAX - 1; + + T ("%*s", width, s); + T ("%*sX", width, s); + T ("%*s%*s", width, s, width, s); + T ("X%*sY%*sZ", width, s, width, s); + + if (width < 4096) + width = 4096; + + T ("%*s", width, s); /* { dg-warning "directive output between 4096 and \[0-9\]+ bytes exceeds minimum required size of 4095" } */ +} Index: testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c =================================================================== --- testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c (revision 268525) +++ testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c (working copy) @@ -166,11 +166,17 @@ void test_string_checked (const char *s, const str T (-1, "%s%s", ar->a4k, ar->ax); /* Verify that an array that fits a string longer than 4095 bytes - does trigger a warning. */ - T (-1, "%-s", ar->a4kp1); /* { dg-warning "directive output between 0 and 4096 bytes may exceed minimum required size of 4095" } */ + does not trigger a warning. (No known implementation has trouble + with this). */ + T (-1, "%s", ar->a4kp1); - /* Also verify that a %s directive with width greater than 4095 - triggers a warning even if the argument is not longer than 4k. */ + /* Verify that a %s directive with width greater than 4095 does + trigger a warning even if the string argument is not longer + than 4k. Glibc only has trouble with directives whose width + or precision exceeds 64K or so: + https://bugzilla.redhat.com/show_bug.cgi?id=441945 * + but hardcoding that as the limit and assuming no other + implementation has a lower one seems unwise. */ T (-1, "%*s", 4096, ar->a4k); /* { dg-warning "directive output of 4096 bytes exceeds minimum required size of 4095" } */ /* Verify that precision constrains the putput and suppresses the 4k @@ -190,5 +196,7 @@ void test_string_checked (const char *s, const str T (-1, "%s %s %s", ar->a4k, ar->a4k, ar->a4k); T (-1, "%s %s %s", ar->ax, ar->ax, ar->ax); - T (-1, "%-s", ar->amax); /* { dg-warning "directive output between 0 and \[0-9\]+ bytes may exceed minimum required size of 4095" } */ + /* Similar to the above, verify there's no warning for an array + just because its size is INT_MAX bytes. */ + T (-1, "%s", ar->amax); }