Commit 3812f460 by Martin Sebor Committed by Martin Sebor

PR middle-end/80364 - sanitizer detects signed integer overflow in gimple-ssa-sprintf.c

gcc/ChangeLog:
	PR middle-end/80364
	* gimple-ssa-sprintf.c (get_int_range): Remove second argument and
	always use the int type.  Use INTEGRAL_TYPE_P() rather than testing
	for INTEGER_TYPE.
	(directive::set_width, directive::set_precision, format_character):
	Adjust.
	(parse_directive): Use INTEGRAL_TYPE_P() rather than testing for
	INTEGER_TYPE.

gcc/testsuite/ChangeLog:
	PR middle-end/80364
	* gcc.dg/tree-ssa/builtin-sprintf-warn-16.c: New test.

From-SVN: r246846
parent b1c0468f
2017-04-11 Martin Sebor <msebor@redhat.com>
PR middle-end/80364
* gimple-ssa-sprintf.c (get_int_range): Remove second argument and
always use the int type. Use INTEGRAL_TYPE_P() rather than testing
for INTEGER_TYPE.
(directive::set_width, directive::set_precision, format_character):
Adjust.
(parse_directive): Use INTEGRAL_TYPE_P() rather than testing for
INTEGER_TYPE.
2017-04-11 Richard Earnshaw <rearnsha@arm.com> 2017-04-11 Richard Earnshaw <rearnsha@arm.com>
PR target/80389 PR target/80389
......
...@@ -599,8 +599,7 @@ fmtresult::type_max_digits (tree type, int base) ...@@ -599,8 +599,7 @@ fmtresult::type_max_digits (tree type, int base)
} }
static bool static bool
get_int_range (tree, tree, HOST_WIDE_INT *, HOST_WIDE_INT *, get_int_range (tree, HOST_WIDE_INT *, HOST_WIDE_INT *, bool, HOST_WIDE_INT);
bool, HOST_WIDE_INT);
/* Description of a format directive. A directive is either a plain /* Description of a format directive. A directive is either a plain
string or a conversion specification that starts with '%'. */ string or a conversion specification that starts with '%'. */
...@@ -674,7 +673,7 @@ struct directive ...@@ -674,7 +673,7 @@ struct directive
For an indeterminate ARG set width to [0, INT_MAX]. */ For an indeterminate ARG set width to [0, INT_MAX]. */
void set_width (tree arg) void set_width (tree arg)
{ {
get_int_range (arg, integer_type_node, width, width + 1, true, 0); get_int_range (arg, width, width + 1, true, 0);
} }
/* Set both bounds of the precision range to VAL. */ /* Set both bounds of the precision range to VAL. */
...@@ -690,7 +689,7 @@ struct directive ...@@ -690,7 +689,7 @@ struct directive
For an indeterminate ARG set precision to [-1, INT_MAX]. */ For an indeterminate ARG set precision to [-1, INT_MAX]. */
void set_precision (tree arg) void set_precision (tree arg)
{ {
get_int_range (arg, integer_type_node, prec, prec + 1, false, -1); get_int_range (arg, prec, prec + 1, false, -1);
} }
/* Return true if both width and precision are known to be /* Return true if both width and precision are known to be
...@@ -927,25 +926,27 @@ build_intmax_type_nodes (tree *pintmax, tree *puintmax) ...@@ -927,25 +926,27 @@ build_intmax_type_nodes (tree *pintmax, tree *puintmax)
} }
} }
/* Determine the range [*PMIN, *PMAX] that the expression ARG of TYPE /* Determine the range [*PMIN, *PMAX] that the expression ARG is
is in. Return true when the range is a subrange of that of TYPE. in and that is representable in type int.
Whn ARG is null it is as if it had the full range of TYPE. Return true when the range is a subrange of that of int.
When ARG is null it is as if it had the full range of int.
When ABSOLUTE is true the range reflects the absolute value of When ABSOLUTE is true the range reflects the absolute value of
the argument. When ABSOLUTE is false, negative bounds of the argument. When ABSOLUTE is false, negative bounds of
the determined range are replaced with NEGBOUND. */ the determined range are replaced with NEGBOUND. */
static bool static bool
get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
bool absolute, HOST_WIDE_INT negbound) bool absolute, HOST_WIDE_INT negbound)
{ {
/* The type of the result. */
const_tree type = integer_type_node;
bool knownrange = false; bool knownrange = false;
if (!arg) if (!arg)
{ {
*pmin = (TYPE_UNSIGNED (type) *pmin = tree_to_shwi (TYPE_MIN_VALUE (type));
? tree_to_uhwi (TYPE_MIN_VALUE (type)) *pmax = tree_to_shwi (TYPE_MAX_VALUE (type));
: tree_to_shwi (TYPE_MIN_VALUE (type)));
*pmax = tree_to_uhwi (TYPE_MAX_VALUE (type));
} }
else if (TREE_CODE (arg) == INTEGER_CST) else if (TREE_CODE (arg) == INTEGER_CST)
{ {
...@@ -961,10 +962,16 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, ...@@ -961,10 +962,16 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
/* True if the argument's range cannot be determined. */ /* True if the argument's range cannot be determined. */
bool unknown = true; bool unknown = true;
type = TREE_TYPE (arg); tree argtype = TREE_TYPE (arg);
/* Ignore invalid arguments with greater precision that that
of the expected type (e.g., in sprintf("%*i", 12LL, i)).
They will have been detected and diagnosed by -Wformat and
so it's not important to complicate this code to try to deal
with them again. */
if (TREE_CODE (arg) == SSA_NAME if (TREE_CODE (arg) == SSA_NAME
&& TREE_CODE (type) == INTEGER_TYPE) && INTEGRAL_TYPE_P (argtype)
&& TYPE_PRECISION (argtype) <= TYPE_PRECISION (type))
{ {
/* Try to determine the range of values of the integer argument. */ /* Try to determine the range of values of the integer argument. */
wide_int min, max; wide_int min, max;
...@@ -972,27 +979,34 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, ...@@ -972,27 +979,34 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
if (range_type == VR_RANGE) if (range_type == VR_RANGE)
{ {
HOST_WIDE_INT type_min HOST_WIDE_INT type_min
= (TYPE_UNSIGNED (type) = (TYPE_UNSIGNED (argtype)
? tree_to_uhwi (TYPE_MIN_VALUE (type)) ? tree_to_uhwi (TYPE_MIN_VALUE (argtype))
: tree_to_shwi (TYPE_MIN_VALUE (type))); : tree_to_shwi (TYPE_MIN_VALUE (argtype)));
HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (type)); HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype));
*pmin = min.to_shwi (); *pmin = min.to_shwi ();
*pmax = max.to_shwi (); *pmax = max.to_shwi ();
/* Return true if the adjusted range is a subrange of if (*pmin < *pmax)
the full range of the argument's type. */ {
knownrange = type_min < *pmin || *pmax < type_max; /* Return true if the adjusted range is a subrange of
the full range of the argument's type. *PMAX may
unknown = false; be less than *PMIN when the argument is unsigned
and its upper bound is in excess of TYPE_MAX. In
that (invalid) case disregard the range and use that
of the expected type instead. */
knownrange = type_min < *pmin || *pmax < type_max;
unknown = false;
}
} }
} }
/* Handle an argument with an unknown range as if none had been /* Handle an argument with an unknown range as if none had been
provided. */ provided. */
if (unknown) if (unknown)
return get_int_range (NULL_TREE, type, pmin, pmax, absolute, negbound); return get_int_range (NULL_TREE, pmin, pmax, absolute, negbound);
} }
/* Adjust each bound as specified by ABSOLUTE and NEGBOUND. */ /* Adjust each bound as specified by ABSOLUTE and NEGBOUND. */
...@@ -1004,6 +1018,9 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, ...@@ -1004,6 +1018,9 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
*pmin = *pmax = -*pmin; *pmin = *pmax = -*pmin;
else else
{ {
/* Make sure signed overlow is avoided. */
gcc_assert (*pmin != HOST_WIDE_INT_MIN);
HOST_WIDE_INT tmp = -*pmin; HOST_WIDE_INT tmp = -*pmin;
*pmin = 0; *pmin = 0;
if (*pmax < tmp) if (*pmax < tmp)
...@@ -1948,7 +1965,7 @@ format_character (const directive &dir, tree arg) ...@@ -1948,7 +1965,7 @@ format_character (const directive &dir, tree arg)
res.range.min = 0; res.range.min = 0;
HOST_WIDE_INT min, max; HOST_WIDE_INT min, max;
if (get_int_range (arg, integer_type_node, &min, &max, false, 0)) if (get_int_range (arg, &min, &max, false, 0))
{ {
if (min == 0 && max == 0) if (min == 0 && max == 0)
{ {
...@@ -3125,7 +3142,7 @@ parse_directive (pass_sprintf_length::call_info &info, ...@@ -3125,7 +3142,7 @@ parse_directive (pass_sprintf_length::call_info &info,
if (star_width) if (star_width)
{ {
if (TREE_CODE (TREE_TYPE (star_width)) == INTEGER_TYPE) if (INTEGRAL_TYPE_P (TREE_TYPE (star_width)))
dir.set_width (star_width); dir.set_width (star_width);
else else
{ {
...@@ -3140,7 +3157,7 @@ parse_directive (pass_sprintf_length::call_info &info, ...@@ -3140,7 +3157,7 @@ parse_directive (pass_sprintf_length::call_info &info,
if (star_precision) if (star_precision)
{ {
if (TREE_CODE (TREE_TYPE (star_precision)) == INTEGER_TYPE) if (INTEGRAL_TYPE_P (TREE_TYPE (star_precision)))
dir.set_precision (star_precision); dir.set_precision (star_precision);
else else
{ {
......
2017-04-11 Martin Sebor <msebor@redhat.com>
PR middle-end/80364
* gcc.dg/tree-ssa/builtin-sprintf-warn-16.c: New test.
2017-04-11 Martin Liska <mliska@suse.cz> 2017-04-11 Martin Liska <mliska@suse.cz>
PR sanitizer/70878 PR sanitizer/70878
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment