mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-21 05:30:24 +08:00
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.
This commit is contained in:
parent
75e562d2c4
commit
aa353bd9a0
@ -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
|
||||
|
28
gcc/testsuite/gcc.dg/Wformat-overflow1.c
Normal file
28
gcc/testsuite/gcc.dg/Wformat-overflow1.c
Normal file
@ -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);
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user