PR tree-optimization/78775 - [7 Regression] ICE in maybe_warn_alloc_args_overflow

gcc/ChangeLog:

	PR tree-optimization/78775
	* builtins.c (get_size_range): Move...
	* calls.c: ...to here.
	(alloc_max_size): Accept zero argument.
	(operand_signed_p): Remove.
	(maybe_warn_alloc_args_overflow): Call get_size_range.
	* calls.h (get_size_range): Declare.

gcc/testsuite/ChangeLog:

	PR tree-optimization/78775
	* gcc.dg/attr-alloc_size-4.c: Add test cases.
	* gcc.dg/attr-alloc_size-10.c: New test.
	* gcc.dg/attr-alloc_size-11.c: New test.
	* gcc.dg/builtin-stringop-chk-7.c: New test.
	* gcc.dg/pr78775.c: New test.
	* gcc.dg/pr78973-2.c: New test.
	* gcc.dg/pr78973.c: New test.

From-SVN: r244290
This commit is contained in:
Martin Sebor 2017-01-10 21:02:07 +00:00 committed by Martin Sebor
parent 5d58291930
commit c16880eff0
12 changed files with 520 additions and 176 deletions

View File

@ -1,3 +1,13 @@
2017-01-10 Martin Sebor <msebor@redhat.com>
PR tree-optimization/78775
* builtins.c (get_size_range): Move...
* calls.c: ...to here.
(alloc_max_size): Accept zero argument.
(operand_signed_p): Remove.
(maybe_warn_alloc_args_overflow): Call get_size_range.
* calls.h (get_size_range): Declare.
2017-01-10 Joe Seymour <joe.s@somniumtech.com>
* config/msp430/driver-msp430.c (msp430_mcu_data): Sync with data

View File

@ -3031,42 +3031,6 @@ expand_builtin_memcpy_args (tree dest, tree src, tree len, rtx target, tree exp)
return dest_addr;
}
/* Fill the 2-element RANGE array with the minimum and maximum values
EXP is known to have and return true, otherwise null and return
false. */
static bool
get_size_range (tree exp, tree range[2])
{
if (tree_fits_uhwi_p (exp))
{
range[0] = range[1] = exp;
return true;
}
if (TREE_CODE (exp) == SSA_NAME)
{
wide_int min, max;
enum value_range_type range_type = get_range_info (exp, &min, &max);
if (range_type == VR_RANGE)
{
/* Interpret the bound in the variable's type. */
range[0] = wide_int_to_tree (TREE_TYPE (exp), min);
range[1] = wide_int_to_tree (TREE_TYPE (exp), max);
return true;
}
else if (range_type == VR_ANTI_RANGE)
{
/* FIXME: Handle anti-ranges. */
}
}
range[0] = NULL_TREE;
range[1] = NULL_TREE;
return false;
}
/* Try to verify that the sizes and lengths of the arguments to a string
manipulation function given by EXP are within valid bounds and that
the operation does not lead to buffer overflow. Arguments other than

View File

@ -1197,92 +1197,144 @@ alloc_max_size (void)
{
alloc_object_size_limit = TYPE_MAX_VALUE (ssizetype);
unsigned HOST_WIDE_INT unit = 1;
char *end;
errno = 0;
unsigned HOST_WIDE_INT limit
= warn_alloc_size_limit ? strtoull (warn_alloc_size_limit, &end, 10) : 0;
if (limit && !errno)
if (warn_alloc_size_limit)
{
if (end && *end)
{
/* Numeric option arguments are at most INT_MAX. Make it
possible to specify a larger value by accepting common
suffixes. */
if (!strcmp (end, "kB"))
unit = 1000;
else if (!strcasecmp (end, "KiB") || strcmp (end, "KB"))
unit = 1024;
else if (!strcmp (end, "MB"))
unit = 1000LU * 1000;
else if (!strcasecmp (end, "MiB"))
unit = 1024LU * 1024;
else if (!strcasecmp (end, "GB"))
unit = 1000LU * 1000 * 1000;
else if (!strcasecmp (end, "GiB"))
unit = 1024LU * 1024 * 1024;
else if (!strcasecmp (end, "TB"))
unit = 1000LU * 1000 * 1000 * 1000;
else if (!strcasecmp (end, "TiB"))
unit = 1024LU * 1024 * 1024 * 1024;
else if (!strcasecmp (end, "PB"))
unit = 1000LU * 1000 * 1000 * 1000 * 1000;
else if (!strcasecmp (end, "PiB"))
unit = 1024LU * 1024 * 1024 * 1024 * 1024;
else if (!strcasecmp (end, "EB"))
unit = 1000LU * 1000 * 1000 * 1000 * 1000 * 1000;
else if (!strcasecmp (end, "EiB"))
unit = 1024LU * 1024 * 1024 * 1024 * 1024 * 1024;
else
unit = 0;
}
char *end = NULL;
errno = 0;
unsigned HOST_WIDE_INT unit = 1;
unsigned HOST_WIDE_INT limit
= strtoull (warn_alloc_size_limit, &end, 10);
if (unit)
alloc_object_size_limit = build_int_cst (ssizetype, limit * unit);
if (!errno)
{
if (end && *end)
{
/* Numeric option arguments are at most INT_MAX. Make it
possible to specify a larger value by accepting common
suffixes. */
if (!strcmp (end, "kB"))
unit = 1000;
else if (!strcasecmp (end, "KiB") || strcmp (end, "KB"))
unit = 1024;
else if (!strcmp (end, "MB"))
unit = 1000LU * 1000;
else if (!strcasecmp (end, "MiB"))
unit = 1024LU * 1024;
else if (!strcasecmp (end, "GB"))
unit = 1000LU * 1000 * 1000;
else if (!strcasecmp (end, "GiB"))
unit = 1024LU * 1024 * 1024;
else if (!strcasecmp (end, "TB"))
unit = 1000LU * 1000 * 1000 * 1000;
else if (!strcasecmp (end, "TiB"))
unit = 1024LU * 1024 * 1024 * 1024;
else if (!strcasecmp (end, "PB"))
unit = 1000LU * 1000 * 1000 * 1000 * 1000;
else if (!strcasecmp (end, "PiB"))
unit = 1024LU * 1024 * 1024 * 1024 * 1024;
else if (!strcasecmp (end, "EB"))
unit = 1000LU * 1000 * 1000 * 1000 * 1000 * 1000;
else if (!strcasecmp (end, "EiB"))
unit = 1024LU * 1024 * 1024 * 1024 * 1024 * 1024;
else
unit = 0;
}
if (unit)
alloc_object_size_limit
= build_int_cst (ssizetype, limit * unit);
}
}
}
return alloc_object_size_limit;
}
/* Return true if the type of OP is signed, looking through any casts
to an unsigned type. */
/* Return true when EXP's range can be determined and set RANGE[] to it
after adjusting it if necessary to make EXP a valid size argument to
an allocation function declared with attribute alloc_size (whose
argument may be signed), or to a string manipulation function like
memset. */
static bool
operand_signed_p (tree op)
bool
get_size_range (tree exp, tree range[2])
{
if (TREE_CODE (op) == SSA_NAME)
if (tree_fits_uhwi_p (exp))
{
gimple *def = SSA_NAME_DEF_STMT (op);
if (is_gimple_assign (def))
{
/* In an assignment involving a cast, ignore the type
of the cast and consider the type of its operand. */
tree_code code = gimple_assign_rhs_code (def);
if (code == NOP_EXPR)
op = gimple_assign_rhs1 (def);
}
else if (gimple_code (def) == GIMPLE_PHI)
{
/* In a phi, a constant argument may be unsigned even
if in the source it's signed and negative. Ignore
those and consider the result of a phi signed if
all its non-constant operands are. */
unsigned nargs = gimple_phi_num_args (def);
for (unsigned i = 0; i != nargs; ++i)
{
tree op = gimple_phi_arg_def (def, i);
if (TREE_CODE (op) != INTEGER_CST
&& !operand_signed_p (op))
return false;
}
/* EXP is a constant. */
range[0] = range[1] = exp;
return true;
}
return true;
wide_int min, max;
enum value_range_type range_type
= (TREE_CODE (exp) == SSA_NAME
? get_range_info (exp, &min, &max) : VR_VARYING);
if (range_type == VR_VARYING)
{
/* No range information available. */
range[0] = NULL_TREE;
range[1] = NULL_TREE;
return false;
}
tree exptype = TREE_TYPE (exp);
unsigned expprec = TYPE_PRECISION (exptype);
wide_int wzero = wi::zero (expprec);
wide_int wmaxval = wide_int (TYPE_MAX_VALUE (exptype));
bool signed_p = !TYPE_UNSIGNED (exptype);
if (range_type == VR_ANTI_RANGE)
{
if (signed_p)
{
if (wi::les_p (max, wzero))
{
/* EXP is not in a strictly negative range. That means
it must be in some (not necessarily strictly) positive
range which includes zero. Since in signed to unsigned
conversions negative values end up converted to large
positive values, and otherwise they are not valid sizes,
the resulting range is in both cases [0, TYPE_MAX]. */
min = wzero;
max = wmaxval;
}
else if (wi::les_p (min - 1, wzero))
{
/* EXP is not in a negative-positive range. That means EXP
is either negative, or greater than max. Since negative
sizes are invalid make the range [MAX + 1, TYPE_MAX]. */
min = max + 1;
max = wmaxval;
}
else
{
max = min - 1;
min = wzero;
}
}
else if (wi::eq_p (wzero, min - 1))
{
/* EXP is unsigned and not in the range [1, MAX]. That means
it's either zero or greater than MAX. Even though 0 would
normally be detected by -Walloc-zero set the range to
[MAX, TYPE_MAX] so that when MAX is greater than the limit
the whole range is diagnosed. */
min = max + 1;
max = wmaxval;
}
else
{
max = min - 1;
min = wzero;
}
}
return !TYPE_UNSIGNED (TREE_TYPE (op));
range[0] = wide_int_to_tree (exptype, min);
range[1] = wide_int_to_tree (exptype, max);
return true;
}
/* Diagnose a call EXP to function FN decorated with attribute alloc_size
@ -1316,8 +1368,8 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
if (tree_int_cst_lt (args[i], integer_zero_node))
{
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"argument %i value %qE is negative",
idx[i] + 1, args[i]);
"%Kargument %i value %qE is negative",
exp, idx[i] + 1, args[i]);
}
else if (integer_zerop (args[i]))
{
@ -1334,8 +1386,8 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
&& !lookup_attribute ("returns_nonnull",
TYPE_ATTRIBUTES (TREE_TYPE (fn)))))
warned = warning_at (loc, OPT_Walloc_zero,
"argument %i value is zero",
idx[i] + 1);
"%Kargument %i value is zero",
exp, idx[i] + 1);
}
else if (tree_int_cst_lt (maxobjsize, args[i]))
{
@ -1351,79 +1403,31 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
continue;
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"argument %i value %qE exceeds "
"%Kargument %i value %qE exceeds "
"maximum object size %E",
idx[i] + 1, args[i], maxobjsize);
exp, idx[i] + 1, args[i], maxobjsize);
}
}
else if (TREE_CODE (args[i]) == SSA_NAME)
else if (TREE_CODE (args[i]) == SSA_NAME
&& get_size_range (args[i], argrange[i]))
{
tree type = TREE_TYPE (args[i]);
wide_int min, max;
value_range_type range_type = get_range_info (args[i], &min, &max);
if (range_type == VR_RANGE)
{
argrange[i][0] = wide_int_to_tree (type, min);
argrange[i][1] = wide_int_to_tree (type, max);
}
else if (range_type == VR_ANTI_RANGE)
{
/* For an anti-range, if the type of the formal argument
is unsigned and the bounds of the range are of opposite
signs when interpreted as signed, check to see if the
type of the actual argument is signed. If so, the lower
bound must be taken to be zero (rather than a large
positive value corresonding to the actual lower bound
interpreted as unsigned) and there is nothing else that
can be inferred from it. */
--min;
++max;
wide_int zero = wi::uhwi (0, TYPE_PRECISION (type));
if (TYPE_UNSIGNED (type)
&& wi::lts_p (zero, min) && wi::lts_p (max, zero)
&& operand_signed_p (args[i]))
continue;
argrange[i][0] = wide_int_to_tree (type, max);
argrange[i][1] = wide_int_to_tree (type, min);
/* Verify that the anti-range doesn't make all arguments
invalid (treat the anti-range ~[0, 0] as invalid). */
if (tree_int_cst_lt (maxobjsize, argrange[i][0])
&& tree_int_cst_le (argrange[i][1], integer_zero_node))
{
warned
= warning_at (loc, OPT_Walloc_size_larger_than_,
(TYPE_UNSIGNED (type)
? G_("argument %i range [%E, %E] exceeds "
"maximum object size %E")
: G_("argument %i range [%E, %E] is both "
"negative and exceeds maximum object "
"size %E")),
idx[i] + 1, argrange[i][0],
argrange[i][1], maxobjsize);
}
continue;
}
else
continue;
/* Verify that the argument's range is not negative (including
upper bound of zero). */
if (tree_int_cst_lt (argrange[i][0], integer_zero_node)
&& tree_int_cst_le (argrange[i][1], integer_zero_node))
{
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"argument %i range [%E, %E] is negative",
idx[i] + 1, argrange[i][0], argrange[i][1]);
"%Kargument %i range [%E, %E] is negative",
exp, idx[i] + 1,
argrange[i][0], argrange[i][1]);
}
else if (tree_int_cst_lt (maxobjsize, argrange[i][0]))
{
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"argument %i range [%E, %E] exceeds "
"%Kargument %i range [%E, %E] exceeds "
"maximum object size %E",
idx[i] + 1, argrange[i][0], argrange[i][1],
exp, idx[i] + 1,
argrange[i][0], argrange[i][1],
maxobjsize);
}
}
@ -1450,15 +1454,15 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
if (vflow)
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"product %<%E * %E%> of arguments %i and %i "
"%Kproduct %<%E * %E%> of arguments %i and %i "
"exceeds %<SIZE_MAX%>",
argrange[0][0], argrange[1][0],
exp, argrange[0][0], argrange[1][0],
idx[0] + 1, idx[1] + 1);
else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod))
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"product %<%E * %E%> of arguments %i and %i "
"%Kproduct %<%E * %E%> of arguments %i and %i "
"exceeds maximum object size %E",
argrange[0][0], argrange[1][0],
exp, argrange[0][0], argrange[1][0],
idx[0] + 1, idx[1] + 1,
maxobjsize);

View File

@ -38,5 +38,6 @@ extern bool pass_by_reference (CUMULATIVE_ARGS *, machine_mode,
extern bool reference_callee_copied (CUMULATIVE_ARGS *, machine_mode,
tree, bool);
extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]);
extern bool get_size_range (tree, tree[2]);
#endif // GCC_CALLS_H

View File

@ -1,3 +1,14 @@
2017-01-10 Martin Sebor <msebor@redhat.com>
PR tree-optimization/78775
* gcc.dg/attr-alloc_size-4.c: Add test cases.
* gcc.dg/attr-alloc_size-10.c: New test.
* gcc.dg/attr-alloc_size-11.c: New test.
* gcc.dg/builtin-stringop-chk-7.c: New test.
* gcc.dg/pr78775.c: New test.
* gcc.dg/pr78973-2.c: New test.
* gcc.dg/pr78973.c: New test.
2017-01-10 Jeff Law <law@redhat.com>
PR tree-optimization/77766

View File

@ -0,0 +1,142 @@
/* Verify that -Walloc-size-greater-than doesn't cause false positives
for anti-ranges. Note that not all of the statements used to create
anti-ranges below result in the argument being represented as an anti
range.
{ dg-do compile }
{ dg-options "-O2 -Walloc-size-larger-than=12" } */
#define SCHAR_MAX __SCHAR_MAX__
#define SCHAR_MIN (-SCHAR_MAX - 1)
#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
#define SHRT_MAX __SHRT_MAX__
#define SHRT_MIN (-SHRT_MAX - 1)
#define USHRT_MAX (SHRT_MAX * 2 + 1)
#define INT_MAX __INT_MAX__
#define INT_MIN (-INT_MAX - 1)
#define UINT_MAX (INT_MAX * 2U + 1)
#define LONG_MAX __LONG_MAX__
#define LONG_MIN (-LONG_MAX - 1)
#define ULONG_MAX (LONG_MAX * 2LU + 1)
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
#define SIZE_MAX __SIZE_MAX__
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
#define CONCAT(a, b) a ## b
#define CAT(a, b) CONCAT (a, b)
/* Macro to generate a unique function to test the anti-range
~[MIN, MAX] for type T. */
#define TEST(T, min, max) \
void* CAT (test_anti_range_, __LINE__)(T n) \
{ \
extern void* CAT (alloc_anti_range_, __LINE__)(T) \
__attribute__ ((alloc_size (1))); \
if (min <= n && n <= max) \
n = min - 1; \
return CAT (alloc_anti_range_, __LINE__)(n); \
} typedef void dummy /* Require a semicolon. */
/* Verify the anti-range ~[TYPE_MAX - 1, TYPE_MAX - 1]. */
TEST (signed char, SCHAR_MAX - 1, SCHAR_MAX - 1);
TEST (unsigned char, UCHAR_MAX - 1, UCHAR_MAX - 1);
TEST (short, SHRT_MAX - 1, SHRT_MAX - 1);
TEST (unsigned short, USHRT_MAX - 1, USHRT_MAX - 1);
TEST (int, INT_MAX - 1, INT_MAX - 1);
TEST (unsigned, UINT_MAX - 1, UINT_MAX - 1);
TEST (long, LONG_MAX - 1, LONG_MAX - 1);
TEST (unsigned long, ULONG_MAX - 1, ULONG_MAX - 1);
TEST (ptrdiff_t, PTRDIFF_MAX - 1, PTRDIFF_MAX - 1);
TEST (size_t, SIZE_MAX - 1, SIZE_MAX - 1);
/* Verify ~[0, 0]. */
TEST (signed char, 0, 0);
TEST (unsigned char, 0, 0);
TEST (short, 0, 0);
TEST (unsigned short, 0, 0);
TEST (int, 0, 0);
TEST (unsigned, 0, 0);
TEST (long, 0, 0);
TEST (unsigned long, 0, 0);
TEST (ptrdiff_t, 0, 0);
TEST (size_t, 0, 0);
/* Verify ~[1, 1]. */
TEST (signed char, 1, 1);
TEST (unsigned char, 1, 1);
TEST (short, 1, 1);
TEST (unsigned short, 1, 1);
TEST (int, 1, 1);
TEST (unsigned, 1, 1);
TEST (long, 1, 1);
TEST (unsigned long, 1, 1);
TEST (ptrdiff_t, 1, 1);
TEST (size_t, 1, 1);
/* Verify ~[TYPE_MAX - 2, TYPE_MAX - 1]. */
TEST (signed char, SCHAR_MAX - 2, SCHAR_MAX - 1);
TEST (unsigned char, UCHAR_MAX - 2, UCHAR_MAX - 1);
TEST (short, SHRT_MAX - 2, SHRT_MAX - 1);
TEST (unsigned short, USHRT_MAX - 2, USHRT_MAX - 1);
TEST (int, INT_MAX - 2, INT_MAX - 1);
TEST (unsigned, UINT_MAX - 2, UINT_MAX - 1);
TEST (long, LONG_MAX - 2, LONG_MAX - 1);
TEST (unsigned long, ULONG_MAX - 2, ULONG_MAX - 1);
TEST (ptrdiff_t, PTRDIFF_MAX - 2, PTRDIFF_MAX - 1);
TEST (size_t, SIZE_MAX - 2, SIZE_MAX - 1);
/* Verify ~[0, 2]. */
TEST (signed char, 0, 2);
TEST (unsigned char, 0, 2);
TEST (short, 0, 2);
TEST (unsigned short, 0, 2);
TEST (int, 0, 2);
TEST (unsigned int, 0, 2);
TEST (long, 0, 2);
TEST (unsigned long, 0, 2);
TEST (ptrdiff_t, 0, 2);
TEST (size_t, 0, 2);
/* Verify the signed anti-range ~[TYPE_MIN - 2, -1]. */
TEST (signed char, SCHAR_MIN + 2, -1);
TEST (short, SHRT_MIN + 2, -1);
TEST (int, INT_MIN + 2, -1);
TEST (long, LONG_MIN + 2, -1);
TEST (ptrdiff_t, PTRDIFF_MIN + 2, -1);
/* Verify the signed anti-range ~[TYPE_MIN - 2, 0]. */
TEST (signed char, SCHAR_MIN + 2, 0);
TEST (short, SHRT_MIN + 2, 0);
TEST (int, INT_MIN + 2, 0);
TEST (long, LONG_MIN + 2, 0);
TEST (ptrdiff_t, PTRDIFF_MIN + 2, 0);
/* Verify the signed anti-range ~[TYPE_MIN - 2, 1]. */
TEST (signed char, SCHAR_MIN + 2, 1);
TEST (short, SHRT_MIN + 2, 1);
TEST (int, INT_MIN + 2, 1);
TEST (long, LONG_MIN + 2, 1);
TEST (ptrdiff_t, PTRDIFF_MIN + 2, 1);
/* Verify the signed anti-range ~[TYPE_MIN - 2, 2]. */
TEST (signed char, SCHAR_MIN + 2, 2);
TEST (short, SHRT_MIN + 2, 2);
TEST (int, INT_MIN + 2, 2);
TEST (long, LONG_MIN + 2, 2);
TEST (ptrdiff_t, PTRDIFF_MIN + 2, 2);
/* Verify the signed anti-range ~[-1, 2]. */
TEST (signed char, -1, 2);
TEST (short, -1, 2);
TEST (int, -1, 2);
TEST (long, -1, 2);
TEST (ptrdiff_t, 01, 2);

View File

@ -0,0 +1,69 @@
/* Verify that -Walloc-size-greater-than doesn't cause false positives
for anti-ranges. Note that not all of the statements below result
in the argument being represented as an anti-range.
{ dg-do compile }
{ dg-options "-O2 -Walloc-size-larger-than=12 -ftrack-macro-expansion=0" } */
#define SCHAR_MAX __SCHAR_MAX__
#define SCHAR_MIN (-SCHAR_MAX - 1)
#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
#define SHRT_MAX __SHRT_MAX__
#define SHRT_MIN (-SHRT_MAX - 1)
#define USHRT_MAX (SHRT_MAX * 2 + 1)
#define INT_MAX __INT_MAX__
#define INT_MIN (-INT_MAX - 1)
#define UINT_MAX (INT_MAX * 2U + 1)
#define LONG_MAX __LONG_MAX__
#define LONG_MIN (-LONG_MAX - 1)
#define ULONG_MAX (LONG_MAX * 2LU + 1)
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
#define SIZE_MAX __SIZE_MAX__
#define ALLOC_MAX 12
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
#define CONCAT(a, b) a ## b
#define CAT(a, b) CONCAT (a, b)
/* Macro to generate a unique function to test the anti-range
~[MIN, MAX] for type T. */
#define TEST(T, min, max) \
void* CAT (test_anti_range_, __LINE__)(T n) \
{ \
extern void* CAT (alloc_anti_range_, __LINE__)(T) \
__attribute__ ((alloc_size (1))); \
if (min <= n && n <= max) \
n = min - 1; \
return CAT (alloc_anti_range_, __LINE__)(n); \
} typedef void dummy /* Require a semicolon. */
/* The following tests fail because of missing range information. */
TEST (signed char, SCHAR_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for signed char" { xfail *-*-* } } */
TEST (short, SHRT_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for short" { xfail *-*-* } } */
TEST (int, INT_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, -3, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, -2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, -1, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, 0, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, 1, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, 1, INT_MAX - 1); /* { dg-warning "argument 1 range \\\[\[0-9\]+, \[0-9\]+\\\] exceeds maximum object size 12" } */
/* The following two aren't necessarily anti-ranges. */
TEST (int, 1, INT_MAX); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
TEST (int, 0, INT_MAX); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -1\\\] is negative" } */
TEST (long, LONG_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (ptrdiff_t, PTRDIFF_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (unsigned, 0, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (unsigned long, 0, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (size_t, 0, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */

View File

@ -128,15 +128,22 @@ test_int_range (int n)
sink (f_int_1 (SR (min, 1234)));
sink (f_int_1 (SR (-2, -1))); /* { dg-warning "argument 1 range \\\[-2, -1\\\] is negative" } */
sink (f_int_1 (SR (1235, 2345))); /* { dg-warning "argument 1 range \\\[1235, 2345\\\] exceeds maximum object size 1234" } */
sink (f_int_1 (SR (max - 1, max))); /* { dg-warning "argument 1 range \\\[\[0-9\]+, \[0-9\]+\\\] exceeds maximum object size 1234" } */
sink (f_int_1 (SAR (-1, 1)));
sink (f_int_1 (SAR (-2, 12)));
sink (f_int_1 (SAR (-3, 123)));
sink (f_int_1 (SAR (-4, 1234))); /* { dg-warning "argument 1 range \\\[1235, -5\\\] is both negative and exceeds maximum object size 1234" } */
sink (f_int_1 (SAR (-4, 1234))); /* { dg-warning "argument 1 range \\\[1235, \[0-9\]+\\\] exceeds maximum object size 1234" } */
sink (f_int_1 (SAR (min + 1, 1233)));
sink (f_int_1 (SAR (min + 2, 1235))); /* { dg-warning "argument 1 range \\\[1236, -\[0-9\]+\\\] is both negative and exceeds maximum object size 1234" } */
sink (f_int_1 (SAR (min + 2, 1235))); /* { dg-warning "argument 1 range \\\[1236, \[0-9\]+\\\] exceeds maximum object size 1234" } */
sink (f_int_1 (SAR (0, max))); /* { dg-warning "argument 1 range \\\[-\[0-9\]*, -1\\\] is negative" } */
/* The range below includes zero which would be diagnosed by
-Walloc-size-zero but since all other values are negative it
is diagnosed by -Walloc-size-larger-than. */
sink (f_int_1 (SAR (1, max))); /* { dg-warning "argument 1 range \\\[-\[0-9\]*, 0\\\] is negative" } */
sink (f_int_1 (SAR (2, max)));
}
void

View File

@ -0,0 +1,72 @@
/* Verify that -Wstringop-overflow doesn't cause false positives for
anti-ranges. Note that not all of the statements below result in
the memset argument being represented as an anti-range.
{ dg-do compile }
{ dg-options "-O2 -Wstringop-overflow" } */
#define SCHAR_MAX __SCHAR_MAX__
#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
#define SHRT_MAX __SHRT_MAX__
#define USHRT_MAX (SHRT_MAX * 2 + 1)
#define INT_MAX __INT_MAX__
#define UINT_MAX (INT_MAX * 2U + 1)
#define LONG_MAX __LONG_MAX__
#define ULONG_MAX (LONG_MAX * 2LU + 1)
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define SIZE_MAX __SIZE_MAX__
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
#define TEST_AR_1(T, prefix) \
void test_ar_1_ ## prefix (void *d, T n) \
{ \
if (n == prefix ## _MAX - 1) \
n = prefix ## _MAX - 2; \
__builtin_memset (d, 0, n); \
} typedef void dummy
#define TEST_AR_2(T, prefix) \
void test_ar_2_ ## prefix (void *d, T n) \
{ \
if (prefix ## _MAX - 2 <= n && n <= prefix ## _MAX - 1) \
n = prefix ## _MAX - 3; \
__builtin_memset (d, 0, n); \
} typedef void dummy
/* Verify antirange where MIN == MAX. */
TEST_AR_1 (signed char, SCHAR);
TEST_AR_1 (unsigned char, UCHAR);
TEST_AR_1 (short, SHRT);
TEST_AR_1 (unsigned short, USHRT);
TEST_AR_1 (int, INT);
TEST_AR_1 (unsigned, UINT);
TEST_AR_1 (long, LONG);
TEST_AR_1 (unsigned long, ULONG);
TEST_AR_1 (ptrdiff_t, PTRDIFF);
TEST_AR_1 (size_t, SIZE);
/* Verify antirange where MIN < MAX. */
TEST_AR_2 (signed char, SCHAR);
TEST_AR_2 (unsigned char, UCHAR);
TEST_AR_2 (short, SHRT);
TEST_AR_2 (unsigned short, USHRT);
TEST_AR_2 (int, INT);
TEST_AR_2 (unsigned, UINT);
TEST_AR_2 (long, LONG);
TEST_AR_2 (unsigned long, ULONG);
TEST_AR_2 (ptrdiff_t, PTRDIFF);
TEST_AR_2 (size_t, SIZE);

View File

@ -0,0 +1,19 @@
/* PR c/78775 - [7 Regression] ICE in maybe_warn_alloc_args_overflow
{ dg-do compile }
{ dg-options "-O2" } */
int a, b, *c;
int main (void)
{
unsigned long d = 0;
while (1)
{
switch (b)
case 'S':
d = a;
c = __builtin_malloc (d);
}
return 0;
}

View File

@ -0,0 +1,25 @@
/* PR c/78973 - warning: memcpy: specified size exceeds maximum object
size [-Wstringop-overflow=]
This is a companion test for the bug above that verifies that the correct
range of the int variable is detected.
{ dg-do compile }
{ dg-require-effective-target int32plus }
{ dg-options "-O2 -Walloc-size-larger-than=4" } */
void *p;
void f (int n)
{
if (n <= 4)
p = __builtin_malloc (n);
/* { dg-warning "argument 1 range \\\[\[0-9\]+, \[0-9\]+\\\] exceeds maximum object size 4" "ilp32" { xfail { ! lp64 } } .-1 } */
}
void g (unsigned n)
{
if (n < 5)
n = 5;
f (n);
}

View File

@ -0,0 +1,20 @@
/* PR c/78973 - warning: memcpy: specified size exceeds maximum object size
Test case for what was initially thought to be a false positive but after
deeper investigation turned out to be a true positive.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
void f (void *p, int n)
{
if (n <= 4)
__builtin_memset (p, 0, n); /* { dg-warning "exceeds maximum object size" } */
}
void g (void *d, unsigned n)
{
if (n < 5)
n = 5;
f (d, n);
}