public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "Даниил Александрович Фролов" <frolov.da@phystech.edu>
To: Marek Polacek <polacek@redhat.com>
Cc: "gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>
Subject: Re: -Wformat-overflow handling for %b and %B directives in C2X standard
Date: Thu, 01 Sep 2022 14:41:17 +0500	[thread overview]
Message-ID: <1615351662024992@mail.yandex.ru> (raw)
In-Reply-To: <Yw4lD/SGLr0BN0qP@redhat.com>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: 0001-Support-b-B-for-Wformat-overflow-sprintf-snprintf.patch --]
[-- Type: text/x-diff; name="0001-Support-b-B-for-Wformat-overflow-sprintf-snprintf.patch", Size: 5972 bytes --]

From eb9e8241d99145020ec5c050c918c1ad3abc2701 Mon Sep 17 00:00:00 2001
From: Frolov Daniil <frolov.da@phystech.edu>
Date: Thu, 1 Sep 2022 10:55:01 +0300
Subject: [PATCH] Support %b, %B for -Wformat-overflow (sprintf, snprintf)

gcc/ChangeLog:

	* gimple-ssa-sprintf.cc (fmtresult::type_max_digits): Handle
	base == 2.
	(tree_digits): Likewise.
	(format_integer): Likewise.
	(parse_directive): Add cases for %b and %B directives.

gcc/testsuite/ChangeLog:

	* gcc.dg/Wformat-overflow1.c: New test.
---
 gcc/gimple-ssa-sprintf.cc                | 41 +++++++++++++++---------
 gcc/testsuite/gcc.dg/Wformat-overflow1.c | 28 ++++++++++++++++
 2 files changed, 53 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/Wformat-overflow1.c

diff --git a/gcc/gimple-ssa-sprintf.cc b/gcc/gimple-ssa-sprintf.cc
index a888b5ac7d5..1dd9b0dc46b 100644
--- a/gcc/gimple-ssa-sprintf.cc
+++ b/gcc/gimple-ssa-sprintf.cc
@@ -535,6 +535,8 @@ fmtresult::type_max_digits (tree type, int base)
   unsigned prec = TYPE_PRECISION (type);
   switch (base)
     {
+    case 2:
+      return prec;
     case 8:
       return (prec + 2) / 3;
     case 10:
@@ -804,9 +806,9 @@ ilog (unsigned HOST_WIDE_INT x, int base)
 /* Return the number of bytes resulting from converting into a string
    the INTEGER_CST tree node X in BASE with a minimum of PREC digits.
    PLUS indicates whether 1 for a plus sign should be added for positive
-   numbers, and PREFIX whether the length of an octal ('O') or hexadecimal
-   ('0x') prefix should be added for nonzero numbers.  Return -1 if X cannot
-   be represented.  */
+   numbers, and PREFIX whether the length of an octal ('0') or hexadecimal
+   ('0x') or binary ('0b') prefix should be added for nonzero numbers.
+   Return -1 if X cannot be represented.  */
 
 static HOST_WIDE_INT
 tree_digits (tree x, int base, HOST_WIDE_INT prec, bool plus, bool prefix)
@@ -857,11 +859,11 @@ tree_digits (tree x, int base, HOST_WIDE_INT prec, bool plus, bool prefix)
 
   /* Adjust a non-zero value for the base prefix, either hexadecimal,
      or, unless precision has resulted in a leading zero, also octal.  */
-  if (prefix && absval && (base == 16 || prec <= ndigs))
+  if (prefix && absval)
     {
-      if (base == 8)
+      if (base == 8 && prec <= ndigs)
 	res += 1;
-      else if (base == 16)
+      else if (base == 16 || base == 2) /* 0x...(0X...) or 0b...(0B...).  */
 	res += 2;
     }
 
@@ -1209,7 +1211,7 @@ format_integer (const directive &dir, tree arg, pointer_query &ptr_qry)
 
   /* True when a conversion is preceded by a prefix indicating the base
      of the argument (octal or hexadecimal).  */
-  bool maybebase = dir.get_flag ('#');
+  const bool maybebase = dir.get_flag ('#');
 
   /* True when a signed conversion is preceded by a sign or space.  */
   bool maybesign = false;
@@ -1229,6 +1231,10 @@ format_integer (const directive &dir, tree arg, pointer_query &ptr_qry)
     case 'u':
       base = 10;
       break;
+    case 'b':
+    case 'B':
+      base = 2;
+      break;
     case 'o':
       base = 8;
       break;
@@ -1240,6 +1246,8 @@ format_integer (const directive &dir, tree arg, pointer_query &ptr_qry)
       gcc_unreachable ();
     }
 
+  const unsigned adj = (sign | maybebase) + (base == 2 || base == 16);
+
   /* The type of the "formal" argument expected by the directive.  */
   tree dirtype = NULL_TREE;
 
@@ -1350,11 +1358,9 @@ format_integer (const directive &dir, tree arg, pointer_query &ptr_qry)
       res.range.unlikely = res.range.max;
 
       /* Bump up the counters if WIDTH is greater than LEN.  */
-      res.adjust_for_width_or_precision (dir.width, dirtype, base,
-					 (sign | maybebase) + (base == 16));
+      res.adjust_for_width_or_precision (dir.width, dirtype, base, adj);
       /* Bump up the counters again if PRECision is greater still.  */
-      res.adjust_for_width_or_precision (dir.prec, dirtype, base,
-					 (sign | maybebase) + (base == 16));
+      res.adjust_for_width_or_precision (dir.prec, dirtype, base, adj);
 
       return res;
     }
@@ -1503,17 +1509,15 @@ format_integer (const directive &dir, tree arg, pointer_query &ptr_qry)
 	  if (res.range.min == 1)
 	    res.range.likely += base == 8 ? 1 : 2;
 	  else if (res.range.min == 2
-		   && base == 16
+		   && (base == 16 || base == 2)
 		   && (dir.width[0] == 2 || dir.prec[0] == 2))
 	    ++res.range.likely;
 	}
     }
 
   res.range.unlikely = res.range.max;
-  res.adjust_for_width_or_precision (dir.width, dirtype, base,
-				     (sign | maybebase) + (base == 16));
-  res.adjust_for_width_or_precision (dir.prec, dirtype, base,
-				     (sign | maybebase) + (base == 16));
+  res.adjust_for_width_or_precision (dir.width, dirtype, base, adj);
+  res.adjust_for_width_or_precision (dir.prec, dirtype, base, adj);
 
   return res;
 }
@@ -3725,6 +3729,11 @@ parse_directive (call_info &info,
       dir.fmtfunc = format_integer;
       break;
 
+    case 'b':
+    case 'B':
+      dir.fmtfunc = format_integer;
+      break;
+
     case 'p':
       /* The %p output is implementation-defined.  It's possible
 	 to determine this format but due to extensions (especially
diff --git a/gcc/testsuite/gcc.dg/Wformat-overflow1.c b/gcc/testsuite/gcc.dg/Wformat-overflow1.c
new file mode 100644
index 00000000000..cf9766fae14
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wformat-overflow1.c
@@ -0,0 +1,28 @@
+/*
+    { dg-do compile }
+    { dg-options "-Wformat-overflow -std=c2x" }
+*/
+
+extern int sprintf (char* restrict, const char* restrict, ...);
+
+void test_warn () {
+
+    int n = __INT_MAX__;
+    char dst [5] = {0};
+    sprintf (dst, "%b", n);  /* { dg-warning "-Wformat-overflow" } */
+
+    sprintf (dst, "%#b", n); /* { dg-warning "-Wformat-overflow" } */
+
+}
+
+void test_no_warn () {
+
+    char dst [5] = {0};
+    int n = 8;
+    sprintf (dst, "%b", n);
+
+    char another_dst [34] = {0};
+    n = __INT_MAX__;
+    sprintf (another_dst, "%#b", n);
+
+}
-- 
2.25.1


  reply	other threads:[~2022-09-01  9:41 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-01 19:19 Frolov Daniil
2022-04-01 20:15 ` Marek Polacek
2022-04-06 21:10   ` Frolov Daniil
2022-04-11 21:56     ` Marek Polacek
2022-08-15 16:42       ` Frolov Daniil
2022-08-30 14:56         ` Marek Polacek
2022-09-01  9:41           ` Даниил Александрович Фролов [this message]
2022-11-28 17:36             ` Jeff Law

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1615351662024992@mail.yandex.ru \
    --to=frolov.da@phystech.edu \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=polacek@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).