mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
re PR tree-optimization/79800 (wrong snprintf result range with precision in a narrow negative-positive range)
PR tree-optimization/79800 * gimple-ssa-sprintf.c (format_floating: Add argument. Handle precision in negative-positive range. (format_floating): Call non-const overload with adjusted precision. PR tree-optimization/79800 * gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: Add test cases. * gcc.dg/tree-ssa/pr79800.c: New test. From-SVN: r246151
This commit is contained in:
parent
76ca5f401d
commit
a983542b60
@ -1,3 +1,10 @@
|
||||
2017-03-14 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/79800
|
||||
* gimple-ssa-sprintf.c (format_floating: Add argument. Handle
|
||||
precision in negative-positive range.
|
||||
(format_floating): Call non-const overload with adjusted precision.
|
||||
|
||||
2017-03-14 Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||
|
||||
PR target/79947
|
||||
@ -10,7 +17,6 @@
|
||||
* builtin-attrs.def (ATTR_ALLOC_SIZE_2_NOTHROW_LIST): New macro.
|
||||
* builtins.def (aligned_alloc): Use it.
|
||||
|
||||
|
||||
PR c/79936
|
||||
* Makefile.in (GTFILES): Add calls.c.
|
||||
* calls.c: Include "gt-calls.h".
|
||||
|
@ -1499,11 +1499,13 @@ format_floating_max (tree type, char spec, HOST_WIDE_INT prec)
|
||||
}
|
||||
|
||||
/* Return a range representing the minimum and maximum number of bytes
|
||||
that the directive DIR will output for any argument. This function
|
||||
is used when the directive argument or its value isn't known. */
|
||||
that the directive DIR will output for any argument. PREC gives
|
||||
the adjusted precision range to account for negative precisions
|
||||
meaning the default 6. This function is used when the directive
|
||||
argument or its value isn't known. */
|
||||
|
||||
static fmtresult
|
||||
format_floating (const directive &dir)
|
||||
format_floating (const directive &dir, const HOST_WIDE_INT prec[2])
|
||||
{
|
||||
tree type;
|
||||
|
||||
@ -1532,8 +1534,8 @@ format_floating (const directive &dir)
|
||||
/* The minimum output as determined by flags. It's always at least 1.
|
||||
When plus or space are set the output is preceded by either a sign
|
||||
or a space. */
|
||||
int flagmin = (1 /* for the first digit */
|
||||
+ (dir.get_flag ('+') | dir.get_flag (' ')));
|
||||
unsigned flagmin = (1 /* for the first digit */
|
||||
+ (dir.get_flag ('+') | dir.get_flag (' ')));
|
||||
|
||||
/* When the pound flag is set the decimal point is included in output
|
||||
regardless of precision. Whether or not a decimal point is included
|
||||
@ -1557,14 +1559,13 @@ format_floating (const directive &dir)
|
||||
+ minprec
|
||||
+ 3 /* p+0 */);
|
||||
|
||||
res.range.max = format_floating_max (type, 'a', dir.prec[1]);
|
||||
res.range.max = format_floating_max (type, 'a', prec[1]);
|
||||
res.range.likely = res.range.min;
|
||||
|
||||
/* The unlikely maximum accounts for the longest multibyte
|
||||
decimal point character. */
|
||||
res.range.unlikely = res.range.max;
|
||||
if (dir.prec[0] != dir.prec[1]
|
||||
|| dir.prec[0] == -1 || dir.prec[0] > 0)
|
||||
if (dir.prec[1] > 0)
|
||||
res.range.unlikely += target_mb_len_max () - 1;
|
||||
|
||||
break;
|
||||
@ -1573,23 +1574,18 @@ format_floating (const directive &dir)
|
||||
case 'E':
|
||||
case 'e':
|
||||
{
|
||||
/* Minimum output attributable to precision and, when it's
|
||||
non-zero, decimal point. */
|
||||
HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0;
|
||||
|
||||
/* The minimum output is "[-+]1.234567e+00" regardless
|
||||
of the value of the actual argument. */
|
||||
HOST_WIDE_INT minprec = 6 + !radix /* decimal point */;
|
||||
if ((dir.prec[0] < 0 && dir.prec[1] > -1) || dir.prec[0] == 0)
|
||||
minprec = 0;
|
||||
else if (dir.prec[0] > 0)
|
||||
minprec = dir.prec[0] + !radix /* decimal point */;
|
||||
|
||||
res.range.min = (flagmin
|
||||
+ radix
|
||||
+ minprec
|
||||
+ 2 /* e+ */ + 2);
|
||||
/* MPFR uses a precision of 16 by default for some reason.
|
||||
Set it to the C default of 6. */
|
||||
int maxprec = dir.prec[1] < 0 ? 6 : dir.prec[1];
|
||||
res.range.max = format_floating_max (type, 'e', maxprec);
|
||||
|
||||
res.range.max = format_floating_max (type, 'e', prec[1]);
|
||||
res.range.likely = res.range.min;
|
||||
|
||||
/* The unlikely maximum accounts for the longest multibyte
|
||||
@ -1605,21 +1601,19 @@ format_floating (const directive &dir)
|
||||
case 'F':
|
||||
case 'f':
|
||||
{
|
||||
/* Minimum output attributable to precision and, when it's non-zero,
|
||||
decimal point. */
|
||||
HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0;
|
||||
|
||||
/* The lower bound when precision isn't specified is 8 bytes
|
||||
("1.23456" since precision is taken to be 6). When precision
|
||||
is zero, the lower bound is 1 byte (e.g., "1"). Otherwise,
|
||||
when precision is greater than zero, then the lower bound
|
||||
is 2 plus precision (plus flags). */
|
||||
HOST_WIDE_INT minprec = 0;
|
||||
if (dir.prec[0] < 0)
|
||||
minprec = dir.prec[1] < 0 ? 6 + !radix /* decimal point */ : 0;
|
||||
else if (dir.prec[0])
|
||||
minprec = dir.prec[0] + !radix /* decimal point */;
|
||||
|
||||
res.range.min = flagmin + radix + minprec;
|
||||
|
||||
/* Compute the upper bound for -TYPE_MAX. */
|
||||
res.range.max = format_floating_max (type, 'f', dir.prec[1]);
|
||||
res.range.max = format_floating_max (type, 'f', prec[1]);
|
||||
|
||||
/* The minimum output with unknown precision is a single byte
|
||||
(e.g., "0") but the more likely output is 3 bytes ("0.0"). */
|
||||
@ -1659,6 +1653,8 @@ format_floating (const directive &dir)
|
||||
else if (maxprec < 0)
|
||||
maxprec = 5;
|
||||
}
|
||||
else
|
||||
maxprec = prec[1];
|
||||
|
||||
res.range.max = format_floating_max (type, spec, maxprec);
|
||||
|
||||
@ -1702,9 +1698,6 @@ format_floating (const directive &dir)
|
||||
static fmtresult
|
||||
format_floating (const directive &dir, tree arg)
|
||||
{
|
||||
if (!arg || TREE_CODE (arg) != REAL_CST)
|
||||
return format_floating (dir);
|
||||
|
||||
HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] };
|
||||
|
||||
/* For an indeterminate precision the lower bound must be assumed
|
||||
@ -1767,6 +1760,9 @@ format_floating (const directive &dir, tree arg)
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg || TREE_CODE (arg) != REAL_CST)
|
||||
return format_floating (dir, prec);
|
||||
|
||||
/* The minimum and maximum number of bytes produced by the directive. */
|
||||
fmtresult res;
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
2017-03-14 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/79800
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: Add test cases.
|
||||
* gcc.dg/tree-ssa/pr79800.c: New test.
|
||||
|
||||
2017-03-14 Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||
|
||||
PR target/79947
|
||||
|
@ -113,9 +113,16 @@ void test_unknown_precision_integer (int p, int i, double d)
|
||||
|
||||
void test_unknown_precision_floating (int p, double d)
|
||||
{
|
||||
T ( 0, "%.*a", R (-1, 0), d); /* { dg-warning "between 6 and 24 " } */
|
||||
T ( 6, "%.*a", R (-1, 0), d); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 7, "%.*a", R (-1, 0), d);
|
||||
T ( 7, "%.*a", p, d);
|
||||
T (21, "%.*a", p, 3.141);
|
||||
|
||||
T ( 0, "%.*e", R (-1, 0), d); /* { dg-warning "between 5 and 14 " } */
|
||||
T ( 0, "%.*e", R (-1, 6), d); /* { dg-warning "between 5 and 14 " } */
|
||||
T ( 5, "%.*e", R (-1, 6), d); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 6, "%.*e", R (-1, 6), d);
|
||||
/* "%.0e", 0.0 results in 5 bytes: "0e+00" */
|
||||
T ( 5, "%.*e", p, d); /* { dg-warning "writing a terminating nul" } */
|
||||
/* "%#.0e", 0.0 results in 6 bytes: "0.e+00" */
|
||||
@ -125,6 +132,10 @@ void test_unknown_precision_floating (int p, double d)
|
||||
T ( 6, "%#.*e", p, 3.141); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 7, "%#.*e", p, 3.141);
|
||||
|
||||
T ( 0, "%.*f", R (-1, 0), d); /* { dg-warning "between 1 and 317 " } */
|
||||
T ( 0, "%.*f", R (-1, 6), d); /* { dg-warning "between 1 and 317 " } */
|
||||
T ( 3, "%.*f", R (-1, 6), d); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%.*f", R (-1, 6), d);
|
||||
/* "%.0f", 0.0 results in 1 byte: "0" but precision of at least 1
|
||||
is likely, resulting in "0.0". */
|
||||
T ( 3, "%.*f", p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
@ -138,12 +149,16 @@ void test_unknown_precision_floating (int p, double d)
|
||||
T ( 3, "%#.*f", p, 3.141); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%#.*f", p, 3.141);
|
||||
|
||||
T ( 0, "%.*g", R (-1, 0), d); /* { dg-warning "between 1 and 13 " } */
|
||||
T (12, "%.*g", R (-1, 0), d); /* { dg-warning "may write a terminating nul" } */
|
||||
T (13, "%.*g", R (-1, 0), d);
|
||||
T (12, "%.*g", p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T (12, "%#.*g", p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T (13, "%.*g", p, d);
|
||||
T (13, "%#.*g", p, d);
|
||||
T ( 6, "%#.*g", R (-1, 0), d);/* { dg-warning "may write a terminating nul" } */
|
||||
T ( 7, "%#.*g", R (-1, 0), d);
|
||||
T (12, "%#.*g", R (-1, 0), d);/* { dg-warning "may write a terminating nul" } */
|
||||
T (12, "%#.*g", R (-1, 6), d);/* { dg-warning "may write a terminating nul" } */
|
||||
T (13, "%#.*g", R (-1, 0), d);
|
||||
T ( 6, "%#.*g", R ( 0, 0), d);/* { dg-warning "may write a terminating nul" } */
|
||||
T ( 7, "%#.*g", R ( 0, 0), d);
|
||||
T ( 6, "%#.*g", R ( 0, 1), d);/* { dg-warning "may write a terminating nul" } */
|
||||
|
31
gcc/testsuite/gcc.dg/tree-ssa/pr79800.c
Normal file
31
gcc/testsuite/gcc.dg/tree-ssa/pr79800.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* PR 79800 - wrong snprintf result range with precision in a narrow
|
||||
negative-positive range
|
||||
{ dg-do "run" }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
#define FMT "%.*a"
|
||||
char fmt[] = FMT;
|
||||
|
||||
volatile double x = 1.23456789;
|
||||
|
||||
void f (int p)
|
||||
{
|
||||
if (p < -1 || 0 < p)
|
||||
p = -1;
|
||||
|
||||
char d[30];
|
||||
int n1 = __builtin_sprintf (d, "%.*a", p, x);
|
||||
const char *s = n1 < 20 ? "< 20" : ">= 20";
|
||||
|
||||
if (__builtin_strcmp (s, ">= 20"))
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
volatile int i = -1;
|
||||
|
||||
int main ()
|
||||
{
|
||||
f (i);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user