Commit 8bd9f164 by Martin Sebor Committed by Martin Sebor

PR c/77531 - __attribute__((alloc_size(1,2))) could also warn on multiplication overflow

PR c/77531 - __attribute__((alloc_size(1,2))) could also warn on multiplication overflow
PR c/78284 - warn on malloc with very large arguments

gcc/c-family/ChangeLog:

	PR c/78284
	* c.opt (-Walloc-zero, -Walloc-size-larger-than): New options.

gcc/ChangeLog:

	PR c/78284
	* builtin-attrs.def (ATTR_ALLOC_SIZE, ATTR_RETURNS_NONNULL): New
	identifier tree nodes.
	(ATTR_ALLOCA_SIZE_1_NOTHROW_LEAF_LIST): New attribute list.
	(ATTR_MALLOC_SIZE_1_NOTHROW_LIST): Same.
	(ATTR_MALLOC_SIZE_1_NOTHROW_LEAF_LIST): Same.
	(ATTR_MALLOC_SIZE_1_2_NOTHROW_LEAF_LIST): Same.
	(ATTR_ALLOC_SIZE_2_NOTHROW_LEAF_LIST): Same.
	* builtins.c (expand_builtin_alloca): Call
	maybe_warn_alloc_args_overflow.
	* builtins.def (aligned_alloc, calloc, malloc, realloc):
	Add attribute alloc_size.
	(alloca): Add attribute alloc_size and returns_nonnull.
	* calls.h (maybe_warn_alloc_args_overflow): Declare.
	* calls.c (alloc_max_size, operand_signed_p): New functions.
	(maybe_warn_alloc_args_overflow): Define.
	(initialize_argument_information): Diagnose overflow in functions
	declared with attaribute alloc_size.
	* doc/invoke.texi (Warning Options): Document -Walloc-zero and
	-Walloc-size-larger-than.

gcc/testsuite/ChangeLog:

	PR c/78284
	* gcc.dg/attr-alloc_size-3.c: New test.
	* gcc.dg/attr-alloc_size-4.c: New test.
	* gcc.dg/attr-alloc_size-5.c: New test.
	* gcc.dg/attr-alloc_size-6.c: New test.
	* gcc.dg/attr-alloc_size-7.c: New test.
	* gcc.dg/attr-alloc_size-8.c: New test.
	* gcc.dg/attr-alloc_size-9.c: New test.
	* gcc/testsuite/gcc.dg/errno-1.c: Adjust.

From-SVN: r243470
parent 410aa898
2016-12-08 Martin Sebor <msebor@redhat.com>
PR c/78284
* builtin-attrs.def (ATTR_ALLOC_SIZE, ATTR_RETURNS_NONNULL): New
identifier tree nodes.
(ATTR_ALLOCA_SIZE_1_NOTHROW_LEAF_LIST): New attribute list.
(ATTR_MALLOC_SIZE_1_NOTHROW_LIST): Same.
(ATTR_MALLOC_SIZE_1_NOTHROW_LEAF_LIST): Same.
(ATTR_MALLOC_SIZE_1_2_NOTHROW_LEAF_LIST): Same.
(ATTR_ALLOC_SIZE_2_NOTHROW_LEAF_LIST): Same.
* builtins.c (expand_builtin_alloca): Call
maybe_warn_alloc_args_overflow.
* builtins.def (aligned_alloc, calloc, malloc, realloc):
Add attribute alloc_size.
(alloca): Add attribute alloc_size and returns_nonnull.
* calls.h (maybe_warn_alloc_args_overflow): Declare.
* calls.c (alloc_max_size, operand_signed_p): New functions.
(maybe_warn_alloc_args_overflow): Define.
(initialize_argument_information): Diagnose overflow in functions
declared with attaribute alloc_size.
* doc/invoke.texi (Warning Options): Document -Walloc-zero and
-Walloc-size-larger-than.
2016-12-08 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/78671
......@@ -4797,12 +4797,12 @@ expand_builtin_alloca (tree exp, bool cannot_accumulate)
{
rtx op0;
rtx result;
bool valid_arglist;
unsigned int align;
bool alloca_with_align = (DECL_FUNCTION_CODE (get_callee_fndecl (exp))
tree fndecl = get_callee_fndecl (exp);
bool alloca_with_align = (DECL_FUNCTION_CODE (fndecl)
== BUILT_IN_ALLOCA_WITH_ALIGN);
valid_arglist
bool valid_arglist
= (alloca_with_align
? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
: validate_arglist (exp, INTEGER_TYPE, VOID_TYPE));
......@@ -4810,6 +4810,18 @@ expand_builtin_alloca (tree exp, bool cannot_accumulate)
if (!valid_arglist)
return NULL_RTX;
if ((alloca_with_align && !warn_vla_limit)
|| (!alloca_with_align && !warn_alloca_limit))
{
/* -Walloca-larger-than and -Wvla-larger-than settings override
the more general -Walloc-size-larger-than so unless either of
the former options is specified check the alloca arguments for
overflow. */
tree args[] = { CALL_EXPR_ARG (exp, 0), NULL_TREE };
int idx[] = { 0, -1 };
maybe_warn_alloc_args_overflow (fndecl, exp, args, idx);
}
/* Compute the argument. */
op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
......
2016-12-08 Martin Sebor <msebor@redhat.com>
PR c/78284
* c.opt (-Walloc-zero, -Walloc-size-larger-than): New options.
2016-12-08 Martin Sebor <msebor@redhat.com>
PR c/78165
* c-pretty-print (pp_c_integer_constant): Avoid formatting type
suffix.
......
......@@ -303,6 +303,15 @@ Walloca
C ObjC C++ ObjC++ Var(warn_alloca) Warning
Warn on any use of alloca.
Walloc-size-larger-than=
C ObjC C++ ObjC++ Var(warn_alloc_size_limit) Warning Joined
-Walloc-size-larger-than=<bytes> Warn for calls to allocation functions that
attempt to allocate objects larger than the specified number of bytes.
Walloc-zero
C ObjC C++ ObjC++ Var(warn_alloc_zero) Warning
-Walloc-zero Warn for calls to allocation functions that specify zero bytes.
Walloca-larger-than=
C ObjC C++ ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
-Walloca-larger-than=<number> Warn on unbounded uses of
......
......@@ -48,8 +48,10 @@ along with GCC; see the file COPYING3. If not see
#include "dbgcnt.h"
#include "rtl-iter.h"
#include "tree-chkp.h"
#include "tree-vrp.h"
#include "tree-ssanames.h"
#include "rtl-chkp.h"
#include "intl.h"
/* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */
#define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
......@@ -1181,6 +1183,311 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
}
}
/* The limit set by -Walloc-larger-than=. */
static GTY(()) tree alloc_object_size_limit;
/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than=
setting if the option is specified, or to the maximum object size if it
is not. Return the initialized value. */
static tree
alloc_max_size (void)
{
if (!alloc_object_size_limit)
{
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 (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. */
static bool
operand_signed_p (tree op)
{
if (TREE_CODE (op) == SSA_NAME)
{
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;
}
return true;
}
}
return !TYPE_UNSIGNED (TREE_TYPE (op));
}
/* Diagnose a call EXP to function FN decorated with attribute alloc_size
whose argument numbers given by IDX with values given by ARGS exceed
the maximum object size or cause an unsigned oveflow (wrapping) when
multiplied. When ARGS[0] is null the function does nothing. ARGS[1]
may be null for functions like malloc, and non-null for those like
calloc that are decorated with a two-argument attribute alloc_size. */
void
maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
{
/* The range each of the (up to) two arguments is known to be in. */
tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } };
/* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2. */
tree maxobjsize = alloc_max_size ();
location_t loc = EXPR_LOCATION (exp);
bool warned = false;
/* Validate each argument individually. */
for (unsigned i = 0; i != 2 && args[i]; ++i)
{
if (TREE_CODE (args[i]) == INTEGER_CST)
{
argrange[i][0] = args[i];
argrange[i][1] = args[i];
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]);
}
else if (integer_zerop (args[i]))
{
/* Avoid issuing -Walloc-zero for allocation functions other
than __builtin_alloca that are declared with attribute
returns_nonnull because there's no portability risk. This
avoids warning for such calls to libiberty's xmalloc and
friends.
Also avoid issuing the warning for calls to function named
"alloca". */
if ((DECL_FUNCTION_CODE (fn) == BUILT_IN_ALLOCA
&& IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6)
|| (DECL_FUNCTION_CODE (fn) != BUILT_IN_ALLOCA
&& !lookup_attribute ("returns_nonnull",
TYPE_ATTRIBUTES (TREE_TYPE (fn)))))
warned = warning_at (loc, OPT_Walloc_zero,
"argument %i value is zero",
idx[i] + 1);
}
else if (tree_int_cst_lt (maxobjsize, args[i]))
{
/* G++ emits calls to ::operator new[](SIZE_MAX) in C++98
mode and with -fno-exceptions as a way to indicate array
size overflow. There's no good way to detect C++98 here
so avoid diagnosing these calls for all C++ modes. */
if (i == 0
&& !args[1]
&& lang_GNU_CXX ()
&& DECL_IS_OPERATOR_NEW (fn)
&& integer_all_onesp (args[i]))
continue;
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"argument %i value %qE exceeds "
"maximum object size %E",
idx[i] + 1, args[i], maxobjsize);
}
}
else if (TREE_CODE (args[i]) == SSA_NAME)
{
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]);
}
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 "
"maximum object size %E",
idx[i] + 1, argrange[i][0], argrange[i][1],
maxobjsize);
}
}
}
if (!argrange[0])
return;
/* For a two-argument alloc_size, validate the product of the two
arguments if both of their values or ranges are known. */
if (!warned && tree_fits_uhwi_p (argrange[0][0])
&& argrange[1][0] && tree_fits_uhwi_p (argrange[1][0])
&& !integer_onep (argrange[0][0])
&& !integer_onep (argrange[1][0]))
{
/* Check for overflow in the product of a function decorated with
attribute alloc_size (X, Y). */
unsigned szprec = TYPE_PRECISION (size_type_node);
wide_int x = wi::to_wide (argrange[0][0], szprec);
wide_int y = wi::to_wide (argrange[1][0], szprec);
bool vflow;
wide_int prod = wi::umul (x, y, &vflow);
if (vflow)
warned = warning_at (loc, OPT_Walloc_size_larger_than_,
"product %<%E * %E%> of arguments %i and %i "
"exceeds %<SIZE_MAX%>",
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 "
"exceeds maximum object size %E",
argrange[0][0], argrange[1][0],
idx[0] + 1, idx[1] + 1,
maxobjsize);
if (warned)
{
/* Print the full range of each of the two arguments to make
it clear when it is, in fact, in a range and not constant. */
if (argrange[0][0] != argrange [0][1])
inform (loc, "argument %i in the range [%E, %E]",
idx[0] + 1, argrange[0][0], argrange[0][1]);
if (argrange[1][0] != argrange [1][1])
inform (loc, "argument %i in the range [%E, %E]",
idx[1] + 1, argrange[1][0], argrange[1][1]);
}
}
if (warned)
{
location_t fnloc = DECL_SOURCE_LOCATION (fn);
if (DECL_IS_BUILTIN (fn))
inform (loc,
"in a call to built-in allocation function %qD", fn);
else
inform (fnloc,
"in a call to allocation function %qD declared here", fn);
}
}
/* Issue an error if CALL_EXPR was flagged as requiring
tall-call optimization. */
......@@ -1359,6 +1666,24 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
bitmap_obstack_release (NULL);
/* Extract attribute alloc_size and if set, store the indices of
the corresponding arguments in ALLOC_IDX, and then the actual
argument(s) at those indices in ALLOC_ARGS. */
int alloc_idx[2] = { -1, -1 };
if (tree alloc_size
= (fndecl ? lookup_attribute ("alloc_size",
TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))
: NULL_TREE))
{
tree args = TREE_VALUE (alloc_size);
alloc_idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
if (TREE_CHAIN (args))
alloc_idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
}
/* Array for up to the two attribute alloc_size arguments. */
tree alloc_args[] = { NULL_TREE, NULL_TREE };
/* I counts args in order (to be) pushed; ARGPOS counts in order written. */
for (argpos = 0; argpos < num_actuals; i--, argpos++)
{
......@@ -1595,6 +1920,20 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
targetm.calls.function_arg_advance (args_so_far, TYPE_MODE (type),
type, argpos < n_named_args);
/* Store argument values for functions decorated with attribute
alloc_size. */
if (argpos == alloc_idx[0])
alloc_args[0] = args[i].tree_value;
else if (argpos == alloc_idx[1])
alloc_args[1] = args[i].tree_value;
}
if (alloc_args[0])
{
/* Check the arguments of functions decorated with attribute
alloc_size. */
maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx);
}
}
......
......@@ -37,7 +37,6 @@ extern bool pass_by_reference (CUMULATIVE_ARGS *, machine_mode,
tree, bool);
extern bool reference_callee_copied (CUMULATIVE_ARGS *, machine_mode,
tree, bool);
extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]);
#endif // GCC_CALLS_H
......@@ -257,6 +257,7 @@ Objective-C and Objective-C++ Dialects}.
@gccoptlist{-fsyntax-only -fmax-errors=@var{n} -Wpedantic @gol
-pedantic-errors @gol
-w -Wextra -Wall -Waddress -Waggregate-return @gol
-Walloc-zero -Walloc-size-larger-than=@var{n}
-Walloca -Walloca-larger-than=@var{n} @gol
-Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
-Wno-attributes -Wbool-compare -Wbool-operation @gol
......@@ -5099,6 +5100,27 @@ annotations.
Warn about overriding virtual functions that are not marked with the override
keyword.
@item -Walloc-zero
@opindex Wno-alloc-zero
@opindex Walloc-zero
Warn about calls to allocation functions decorated with attribute
@code{alloc_size} that specify zero bytes, including those to the built-in
forms of the functions @code{aligned_alloc}, @code{alloca}, @code{calloc},
@code{malloc}, and @code{realloc}. Because the behavior of these functions
when called with a zero size differs among implementations (and in the case
of @code{realloc} has been deprecated) relying on it may result in subtle
portability bugs and should be avoided.
@item -Walloc-size-larger-than=@var{n}
Warn about calls to functions decorated with attribute @code{alloc_size}
that attempt to allocate objects larger than the specified number of bytes,
or where the result of the size computation in an integer type with infinite
precision would exceed @code{SIZE_MAX / 2}. The option argument @var{n}
may end in one of the standard suffixes designating a multiple of bytes
such as @code{kB} and @code{KiB} for kilobyte and kibibyte, respectively,
@code{MB} and @code{MiB} for magabyte and mebibyte, and so on.
@xref{Function Attributes}.
@item -Walloca
@opindex Wno-alloca
@opindex Walloca
......
2016-12-08 Martin Sebor <msebor@redhat.com>
PR c/78284
* gcc.dg/attr-alloc_size-3.c: New test.
* gcc.dg/attr-alloc_size-4.c: New test.
* gcc.dg/attr-alloc_size-5.c: New test.
* gcc.dg/attr-alloc_size-6.c: New test.
* gcc.dg/attr-alloc_size-7.c: New test.
* gcc.dg/attr-alloc_size-8.c: New test.
* gcc.dg/attr-alloc_size-9.c: New test.
* gcc/testsuite/gcc.dg/errno-1.c: Adjust.
2016-12-08 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/65173
......
/* PR c/77531 - __attribute__((alloc_size(1,2))) could also warn on
multiplication overflow
PR c/78284 - warn on malloc with very large arguments
Test exercising the ability to detect and diagnose calls to allocation
functions decorated with attribute alloc_size that either overflow or
exceed the default maximum object size (with -Walloc-size-larger-than
not explicitly specified). */
/* { dg-do compile } */
/* { dg-options "-O2 -Wall" } */
#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 - 1L)
#define ULONG_MAX (LONG_MAX * 2LU + 1)
#define LLONG_MAX __LLONG_MAX__
#define LLONG_MIN (-LLONG_MAX - 1LL)
#define ULLONG_MAX (ULLONG_MAX * 2LLU + 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 ALLOC_SIZE(...) __attribute__ ((alloc_size (__VA_ARGS__)))
void* f_uchar_1 (unsigned char) ALLOC_SIZE (1);
void* f_uchar_2 (unsigned char, unsigned char) ALLOC_SIZE (1, 2);
void* f_schar_1 (signed char) ALLOC_SIZE (1);
void* f_schar_2 (signed char, signed char) ALLOC_SIZE (1, 2);
void* f_ushrt_1 (unsigned short) ALLOC_SIZE (1);
void* f_ushrt_2 (unsigned short, unsigned short) ALLOC_SIZE (1, 2);
void* f_shrt_1 (signed short) ALLOC_SIZE (1);
void* f_shrt_2 (signed short, signed short) ALLOC_SIZE (1, 2);
void* f_uint_1 (unsigned) ALLOC_SIZE (1);
void* f_uint_2 (unsigned, unsigned) ALLOC_SIZE (1, 2);
void* f_int_1 (int) ALLOC_SIZE (1);
void* f_int_2 (int, int) ALLOC_SIZE (1, 2);
void* f_ulong_1 (unsigned long) ALLOC_SIZE (1);
void* f_ulong_2 (unsigned long, unsigned long) ALLOC_SIZE (1, 2);
void* f_long_1 (long) ALLOC_SIZE (1);
void* f_long_2 (long, long) ALLOC_SIZE (1, 2);
void* f_ullong_1 (unsigned long long) ALLOC_SIZE (1);
void* f_ullong_2 (unsigned long long, unsigned long long) ALLOC_SIZE (1, 2);
void* f_llong_1 (long long) ALLOC_SIZE (1);
void* f_llong_2 (long long, long long) ALLOC_SIZE (1, 2);
void* f_size_1 (size_t) ALLOC_SIZE (1);
void* f_size_2 (size_t, size_t) ALLOC_SIZE (1, 2);
unsigned long long
unsigned_range (unsigned long long min, unsigned long long max)
{
extern unsigned long long random_unsigned_value (void);
unsigned long long val = random_unsigned_value ();
if (val < min || max < val) val = min;
return val;
}
long long
signed_range (long long min, long long max)
{
extern long long random_signed_value (void);
long long val = random_signed_value ();
if (val < min || max < val) val = min;
return val;
}
unsigned long long
unsigned_anti_range (unsigned long long min, unsigned long long max)
{
extern unsigned long long random_unsigned_value (void);
unsigned long long val = random_unsigned_value ();
if (min <= val && val <= max)
val = min - 1;
return val;
}
long long
signed_anti_range (long long min, long long max)
{
extern long long random_signed_value (void);
long long val = random_signed_value ();
if (min <= val && val <= max)
val = min - 1;
return val;
}
#define UR(min, max) unsigned_range (min, max)
#define SR(min, max) signed_range (min, max)
#define UAR(min, max) unsigned_anti_range (min, max)
#define SAR(min, max) signed_anti_range (min, max)
void sink (void*);
void
test_uchar_cst (void)
{
const unsigned char max = UCHAR_MAX;
sink (f_uchar_1 (0));
sink (f_uchar_1 (1));
sink (f_uchar_1 (max));
sink (f_uchar_2 (0, 0));
sink (f_uchar_2 (0, 1));
sink (f_uchar_2 (1, 0));
sink (f_uchar_2 (1, 1));
sink (f_uchar_2 (0, max));
sink (f_uchar_2 (max, 0));
sink (f_uchar_2 (max, max));
}
void
test_uchar_range (unsigned char n, int i)
{
const unsigned char max = UCHAR_MAX;
sink (f_uchar_1 (n));
sink (f_uchar_1 (UR (0, 1)));
sink (f_uchar_1 (UR (1, max)));
sink (f_uchar_1 (UR (0, max - 1)));
sink (f_uchar_1 (UAR (1, 1)));
sink (f_uchar_1 (UAR (1, max - 1)));
sink (f_uchar_1 (UAR (max - 2, max - 1)));
sink (f_uchar_2 (0, n));
sink (f_uchar_2 (0, i));
sink (f_uchar_2 (n, 0));
sink (f_uchar_2 (i, 0));
sink (f_uchar_2 (1, n));
sink (f_uchar_2 (1, i));
sink (f_uchar_2 (n, 1));
sink (f_uchar_2 (i, 1));
sink (f_uchar_2 (max, n));
sink (f_uchar_2 (max, i));
sink (f_uchar_2 (n, max));
sink (f_uchar_2 (i, max));
sink (f_uchar_2 (n, n));
sink (f_uchar_2 (i, i));
sink (f_uchar_2 (UR (0, 1), UR (0, 1)));
sink (f_uchar_2 (UR (1, 2), UR (1, 2)));
sink (f_uchar_2 (UR (1, max), UR (0, 1)));
sink (f_uchar_2 (UR (0, 1), UR (1, max)));
}
void
test_schar_cst (void)
{
const signed char min = SCHAR_MIN;
const signed char max = SCHAR_MAX;
sink (f_schar_1 (min)); /* { dg-warning "argument 1 value .-\[0-9\]+. is negative" } */
sink (f_schar_1 (-1)); /* { dg-warning "argument 1 value .-1. is negative" } */
sink (f_schar_1 (0));
sink (f_schar_1 (1));
sink (f_schar_1 (max));
sink (f_schar_2 (0, min)); /* { dg-warning "argument 2 value .-\[0-9\]+. is negative" } */
sink (f_schar_2 (min, 0)); /* { dg-warning "argument 1 value .-\[0-9\]+. is negative" } */
sink (f_schar_2 (0, -1)); /* { dg-warning "argument 2 value .-1. is negative" } */
sink (f_schar_2 (-1, 0)); /* { dg-warning "argument 1 value .-1. is negative" } */
}
void
test_schar_range (signed char n)
{
const signed char min = SCHAR_MIN;
const signed char max = SCHAR_MAX;
sink (f_schar_1 (n));
sink (f_schar_1 (SR (min, min + 1))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
sink (f_schar_1 (SR (min, 0))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_schar_1 (SR (-1, 0))); /* { dg-warning "argument 1 range \\\[-1, 0\\\] is negative" } */
sink (f_schar_1 (SR (-1, 1)));
sink (f_schar_1 (SR (0, 1)));
sink (f_schar_1 (SR (0, max - 1)));
sink (f_schar_1 (SR (1, max)));
sink (f_schar_1 (SR (max - 1, max)));
sink (f_schar_2 (n, n));
sink (f_schar_2 (SR (min, min + 1), n)); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
sink (f_schar_2 (n, SR (min, min + 1))); /* { dg-warning "argument 2 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
sink (f_schar_2 (SR (min, min + 1), 0)); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
sink (f_schar_2 (0, SR (min, min + 1))); /* { dg-warning "argument 2 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
sink (f_schar_2 (SR (min, min + 1), min)); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
/* { dg-warning "argument 2 value .-\[0-9\]+. is negative" "argument 2" { target *-*-* } .-1 } */
sink (f_schar_2 (min, SR (min, min + 1))); /* { dg-warning "argument 2 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
/* { dg-warning "argument 1 value .-\[0-9\]+. is negative" "argument 1" { target *-*-* } .-1 } */
sink (f_schar_2 (SR (-1, 0), 0)); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_schar_2 (0, SR (-1, 0))); /* { dg-warning "argument 2 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_schar_2 (SR (-1, 0), 1)); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_schar_2 (1, SR (-1, 0))); /* { dg-warning "argument 2 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_schar_2 (SR (-1, 0), n)); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_schar_2 (n, SR (-1, 0))); /* { dg-warning "argument 2 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_schar_2 (max, SR (1, max)));
sink (f_schar_2 (SR (1, max), max));
}
void
test_ushrt_cst (void)
{
const unsigned short max = USHRT_MAX;
sink (f_ushrt_1 (0));
sink (f_ushrt_1 (1));
sink (f_ushrt_1 (max));
sink (f_ushrt_2 (0, 0));
sink (f_ushrt_2 (0, 1));
sink (f_ushrt_2 (1, 0));
sink (f_ushrt_2 (1, 1));
sink (f_ushrt_2 (0, max));
sink (f_ushrt_2 (max, 0));
#if USHRT_MAX < SIZE_MAX
sink (f_ushrt_2 (max, max));
#endif
}
void
test_ushrt_range (unsigned short n)
{
const unsigned short max = USHRT_MAX;
sink (f_ushrt_1 (n));
sink (f_ushrt_1 (UR (0, 1)));
sink (f_ushrt_1 (UR (1, max - 1)));
sink (f_ushrt_1 (UR (1, max)));
sink (f_ushrt_1 (UR (0, max - 1)));
}
void
test_shrt_cst (void)
{
const short min = SHRT_MIN;
const short max = SHRT_MAX;
sink (f_shrt_1 (min)); /* { dg-warning "argument 1 value .-\[0-9\]+. is negative" } */
sink (f_shrt_1 (-1)); /* { dg-warning "argument 1 value .-1. is negative" } */
sink (f_shrt_1 (0));
sink (f_shrt_1 (1));
sink (f_shrt_1 (max));
}
void
test_shrt_range (short n)
{
const short min = SHRT_MIN;
const short max = SHRT_MAX;
sink (f_shrt_1 (n));
sink (f_shrt_1 (SR (min, min + 1))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
sink (f_shrt_1 (SR (min, 0))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_shrt_1 (SR (-1, 0))); /* { dg-warning "argument 1 range \\\[-1, 0\\\] is negative" } */
sink (f_shrt_1 (SR (-1, 1)));
sink (f_shrt_1 (SR (0, 1)));
sink (f_shrt_1 (SR (0, max - 1)));
sink (f_shrt_1 (SR (1, max)));
sink (f_shrt_1 (SR (max - 1, max)));
}
void
test_uint_cst (void)
{
const unsigned max = UINT_MAX;
sink (f_uint_1 (0));
sink (f_uint_1 (1));
sink (f_uint_1 (max - 1));
sink (f_uint_1 (max));
}
void
test_uint_range (unsigned n)
{
const unsigned max = UINT_MAX;
sink (f_uint_1 (n));
sink (f_uint_1 (UR (0, 1)));
sink (f_uint_1 (UR (0, max - 1)));
sink (f_uint_1 (UR (1, max - 1)));
sink (f_uint_1 (UR (1, max)));
}
void
test_int_cst (void)
{
const int min = INT_MIN;
const int max = INT_MAX;
sink (f_int_1 (min)); /* { dg-warning "argument 1 value .-\[0-9\]+. is negative" } */
sink (f_int_1 (-1)); /* { dg-warning "argument 1 value .-1. is negative" } */
sink (f_int_1 (0));
sink (f_int_1 (1));
sink (f_int_1 (max));
}
void
test_int_range (int n)
{
const int min = INT_MIN;
const int max = INT_MAX;
sink (f_int_1 (n));
sink (f_int_1 (SR (min, min + 1))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -\[0-9\]+\\\] is negative" } */
sink (f_int_1 (SR (min, 0))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
sink (f_int_1 (SR (-1, 0))); /* { dg-warning "argument 1 range \\\[-1, 0\\\] is negative" } */
sink (f_int_1 (SR (-1, 1)));
sink (f_int_1 (SR (0, 1)));
sink (f_int_1 (SR (0, max - 1)));
sink (f_int_1 (SR (1, max)));
sink (f_int_1 (SR (max - 1, max)));
}
void
test_ulong_cst (void)
{
const unsigned long max = ULONG_MAX;
sink (f_ulong_1 (0));
sink (f_ulong_1 (1));
#if ULONG_MAX < SIZE_MAX
sink (f_ulong_1 (max - 1));
sink (f_ulong_1 (max));
#else
(void)&max;
#endif
}
void
test_ulong_range (unsigned long n)
{
const unsigned long max = ULONG_MAX;
sink (f_ulong_1 (n));
sink (f_ulong_1 (UR (0, 1)));
sink (f_ulong_1 (UR (0, max - 1)));
sink (f_ulong_1 (UR (1, max - 1)));
sink (f_ulong_1 (UR (1, max)));
}
void
test_long_cst (void)
{
const long min = LONG_MIN;
const long max = LONG_MAX;
sink (f_long_1 (min)); /* { dg-warning "argument 1 value .-\[0-9\]+l*. is negative" } */
sink (f_long_1 (-1)); /* { dg-warning "argument 1 value .-1l*. is negative" } */
sink (f_long_1 (0));
sink (f_long_1 (1));
sink (f_long_1 (max));
}
void
test_long_range (long n)
{
const long min = LONG_MIN;
const long max = LONG_MAX;
sink (f_long_1 (n));
sink (f_long_1 (SR (min, min + 1))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+l*, -\[0-9\]+l*\\\] is negative" } */
sink (f_long_1 (SR (min, 0))); /* { dg-warning "argument 1 range \\\[-\[0-9\]+l*, 0l*\\\] is negative" } */
sink (f_long_1 (SR (-1, 0))); /* { dg-warning "argument 1 range \\\[-1l*, 0l*\\\] is negative" } */
sink (f_long_1 (SR (-1, 1)));
sink (f_long_1 (SR (0, 1)));
sink (f_long_1 (SR (0, max - 1)));
sink (f_long_1 (SR (1, max)));
sink (f_long_1 (SR (max - 1, max)));
}
void
test_size_cst (void)
{
const size_t max = __SIZE_MAX__;
sink (f_size_1 (0));
sink (f_size_1 (1));
sink (f_size_1 (max - 1)); /* { dg-warning "argument 1 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_1 (max)); /* { dg-warning "argument 1 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (0, max - 1)); /* { dg-warning "argument 2 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (max - 1, 0)); /* { dg-warning "argument 1 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (1, max - 1)); /* { dg-warning "argument 2 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (max - 1, 1)); /* { dg-warning "argument 1 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (max - 1, max - 1)); /* { dg-warning "argument 1 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
/* { dg-warning "argument 2 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" "argument 2" { target *-*-* } .-1 } */
sink (f_size_2 (0, max)); /* { dg-warning "argument 2 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (max, 0)); /* { dg-warning "argument 1 value .\[0-9\]+\[lu\]*. exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (max / 2, 2)); /* { dg-warning "product .\[0-9\]+\[lu\]* \\* \[0-9\]+\[lu\]*. of arguments 1 and 2 exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (max / 2, 3)); /* { dg-warning "product .\[0-9\]+\[lu\]* \\* \[0-9\]+\[lu\]*. of arguments 1 and 2 exceeds .SIZE_MAX." } */
}
void
test_size_range (size_t ui, ptrdiff_t si)
{
const ptrdiff_t smin = PTRDIFF_MIN;
const ptrdiff_t smax = PTRDIFF_MAX;
const size_t umax = SIZE_MAX;
sink (f_size_1 (ui));
sink (f_size_1 (si));
sink (f_size_1 (UR (0, 1)));
sink (f_size_1 (UR (0, umax - 1)));
sink (f_size_1 (UR (1, umax - 1)));
sink (f_size_1 (UR (1, umax)));
sink (f_size_1 (UAR (1, 1)));
/* Since the only valid argument in the anti-range below is zero
a warning is expected even though -Walloc-zero is not specified. */
sink (f_size_1 (UAR (1, umax / 2))); /* { dg-warning "argument 1 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
/* The only valid argument in this range is 1. */
sink (f_size_1 (UAR (2, umax / 2)));
sink (f_size_2 (ui, ui));
sink (f_size_2 (si, si));
sink (f_size_2 (ui, umax / 2));
sink (f_size_2 (si, umax / 2));
sink (f_size_2 (umax / 2, ui));
sink (f_size_2 (umax / 2, si));
sink (f_size_2 (UR (0, 1), umax)); /* { dg-warning "argument 2 value .\[0-9\]+\[lu\]*. exceeds maximum object size " } */
sink (f_size_2 (UR (0, 1), umax / 2));
sink (f_size_2 (UR (0, umax / 2), umax / 2));
sink (f_size_2 (UR (umax / 2 + 1, umax / 2 + 2), ui)); /* { dg-warning "argument 1 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
sink (f_size_2 (ui, UR (umax / 2 + 1, umax / 2 + 2))); /* { dg-warning "argument 2 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
sink (f_size_2 (UR (umax / 2 + 1, umax), UR (umax / 2 + 1, umax))); /* { dg-warning "argument 1 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
/* { dg-warning "argument 2 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " "argument 2" { target *-*-* } .-1 } */
sink (f_size_2 (SR (smin, 1), 1));
sink (f_size_2 (SR (smin, 1), umax / 2));
sink (f_size_2 (SR (-1, smax), 1));
sink (f_size_2 (SR (-1, smax), umax / 2));
sink (f_size_2 (SR (-1, 1), 1));
sink (f_size_2 (SR (-1, 1), umax / 2));
sink (f_size_2 (SR (-9, 9), 1));
sink (f_size_2 (SR (-9, 9), umax / 2));
}
/* PR c/77531 - __attribute__((alloc_size(1,2))) could also warn on
multiplication overflow
PR c/78284 - warn on malloc with very large arguments
Test exercising the ability to detect and diagnose calls to allocation
functions decorated with attribute alloc_size that either overflow or
exceed the maximum object size specified by -Walloc-size-larger-than. */
/* { dg-do compile } */
/* { dg-options "-O2 -Wall -Walloc-size-larger-than=1234" } */
#define INT_MAX __INT_MAX__
#define INT_MIN (-INT_MAX - 1)
#define UINT_MAX (INT_MAX * 2U + 1)
#define SIZE_MAX __SIZE_MAX__
typedef __SIZE_TYPE__ size_t;
#define ALLOC_SIZE(...) __attribute__ ((alloc_size (__VA_ARGS__)))
void* f_uint_1 (unsigned) ALLOC_SIZE (1);
void* f_uint_2 (unsigned, unsigned) ALLOC_SIZE (1, 2);
void* f_int_1 (int) ALLOC_SIZE (1);
void* f_int_2 (int, int) ALLOC_SIZE (1, 2);
void* f_size_1 (size_t) ALLOC_SIZE (1);
void* f_size_2 (size_t, size_t) ALLOC_SIZE (1, 2);
size_t
unsigned_range (size_t min, size_t max)
{
extern size_t random_unsigned_value (void);
size_t val = random_unsigned_value ();
if (val < min || max < val) val = min;
return val;
}
int
signed_range (int min, int max)
{
extern int random_signed_value (void);
int val = random_signed_value ();
if (val < min || max < val) val = min;
return val;
}
size_t
unsigned_anti_range (size_t min, size_t max)
{
extern size_t random_unsigned_value (void);
size_t val = random_unsigned_value ();
if (min <= val && val <= max)
val = min - 1;
return val;
}
int
signed_anti_range (int min, int max)
{
extern int random_signed_value (void);
int val = random_signed_value ();
if (min <= val && val <= max)
val = min - 1;
return val;
}
#define UR(min, max) unsigned_range (min, max)
#define SR(min, max) signed_range (min, max)
#define UAR(min, max) unsigned_anti_range (min, max)
#define SAR(min, max) signed_anti_range (min, max)
void sink (void*);
void
test_uint_cst (void)
{
const unsigned max = UINT_MAX;
sink (f_uint_1 (0));
sink (f_uint_1 (1));
sink (f_uint_1 (1233));
sink (f_uint_1 (1234));
sink (f_uint_1 (1235)); /* { dg-warning "argument 1 value .1235u?. exceeds maximum object size 1234" } */
sink (f_uint_1 (max - 1)); /* { dg-warning "argument 1 value .\[0-9\]+u?. exceeds maximum object size 1234" } */
sink (f_uint_1 (max)); /* { dg-warning "argument 1 value .\[0-9\]+u?. exceeds maximum object size 1234" } */
}
void
test_uint_range (unsigned n)
{
const unsigned max = UINT_MAX;
sink (f_uint_1 (n));
sink (f_uint_1 (UR (0, 1)));
sink (f_uint_1 (UR (0, 1233)));
sink (f_uint_1 (UR (0, 1234)));
sink (f_uint_1 (UR (0, 1235)));
sink (f_uint_1 (UR (1, 1235)));
sink (f_uint_1 (UR (1234, 1235)));
sink (f_uint_1 (UR (1235, 1236))); /* { dg-warning "argument 1 range \\\[\[0-9\]+u?, \[0-9\]+u?\\\] exceeds maximum object size 1234" } */
sink (f_uint_1 (UR (1, max - 1)));
sink (f_uint_1 (UR (1, max)));
}
void
test_int_cst (void)
{
const int min = INT_MIN;
const int max = INT_MAX;
sink (f_int_1 (min)); /* { dg-warning "argument 1 value .-\[0-9\]+. is negative" } */
sink (f_int_1 (-1)); /* { dg-warning "argument 1 value .-1. is negative" } */
sink (f_int_1 (0));
sink (f_int_1 (1));
sink (f_int_1 (1233));
sink (f_int_1 (1234));
sink (f_int_1 (max)); /* { dg-warning "argument 1 value .\[0-9\]+u?. exceeds maximum object size 1234" } */
}
void
test_int_range (int n)
{
const int min = INT_MIN;
const int max = INT_MAX;
sink (f_int_1 (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\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] 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 (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" } */
}
void
test_size_cst (void)
{
const size_t max = __SIZE_MAX__;
sink (f_size_1 (0));
sink (f_size_1 (1));
sink (f_size_2 ( 0, 1234));
sink (f_size_2 ( 1, 1234));
sink (f_size_2 ( 2, 1234)); /* { dg-warning "product .2\[lu\]* \\* 1234\[lu\]*. of arguments 1 and 2 exceeds maximum object size \[0-9\]+" } */
sink (f_size_2 (1234, 1234)); /* { dg-warning "product .1234\[lu\]* \\* 1234\[lu\]*. of arguments 1 and 2 exceeds maximum object size 1234" } */
sink (f_size_2 (1235, 1234)); /* { dg-warning "argument 1 value .1235\[lu\]*. exceeds maximum object size 1234" } */
sink (f_size_2 (1234, 1235)); /* { dg-warning "argument 2 value .1235\[lu\]*. exceeds maximum object size 1234" } */
sink (f_size_2 (1234, max)); /* { dg-warning "argument 2 value .\[0-9\]+\[lu\]*. exceeds maximum object size 1234" } */
sink (f_size_2 (max, 1234)); /* { dg-warning "argument 1 value .\[0-9\]+\[lu\]*. exceeds maximum object size 1234" } */
}
void
test_size_range (size_t n)
{
const size_t max = __SIZE_MAX__;
sink (f_size_1 (n));
sink (f_size_1 (UR (0, 1)));
sink (f_size_1 (UR (0, max - 1)));
sink (f_size_1 (UR (1, max - 1)));
sink (f_size_1 (UR (1, max)));
sink (f_size_1 (UAR (1, 1)));
/* Since the only valid argument in the anti-range below is zero
a warning is expected even though -Walloc-zero is not specified. */
sink (f_size_1 (UAR (1, 1234))); /* { dg-warning "argument 1 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
/* The only valid argument in this range is 1. */
sink (f_size_1 (UAR (2, max / 2)));
sink (f_size_2 (n, n));
sink (f_size_2 (n, 1234));
sink (f_size_2 (1234, n));
sink (f_size_2 (UR (0, 1), 1234));
sink (f_size_2 (UR (0, 1), 1235)); /* { dg-warning "argument 2 value .1235\[lu\]*. exceeds maximum object size 1234" } */
sink (f_size_2 (UR (1235, 1236), n)); /* { dg-warning "argument 1 range \\\[1235\[lu\]*, 1236\[lu\]*\\\] exceeds maximum object size 1234" } */
sink (f_size_2 (UR (1235, 1236), UR (max / 2, max))); /* { dg-warning "argument 1 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
/* { dg-warning "argument 2 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " "argument 2" { target *-*-* } .-1 } */
}
/* PR c/78284 - warn on malloc with very large arguments
Test exercising the ability to detect and diagnose calls to allocation
functions decorated with attribute alloc_size that attempt to allocate
zero bytes. For standard allocation functions the return value is
implementation-defined and so relying on it may be a source of bugs. */
/* { dg-do compile } */
/* { dg-options "-O2 -Wall -Walloc-zero" } */
#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 - 1L)
#define ULONG_MAX (LONG_MAX * 2LU + 1)
#define LLONG_MAX __LLONG_MAX__
#define LLONG_MIN (-LLONG_MAX - 1LL)
#define ULLONG_MAX (ULLONG_MAX * 2LLU + 1)
#define SIZE_MAX __SIZE_MAX__
typedef __SIZE_TYPE__ size_t;
#define ALLOC_SIZE(...) __attribute__ ((alloc_size (__VA_ARGS__)))
void* f_uchar_1 (unsigned char) ALLOC_SIZE (1);
void* f_uchar_2 (unsigned char, unsigned char) ALLOC_SIZE (1, 2);
void* f_schar_1 (signed char) ALLOC_SIZE (1);
void* f_schar_2 (signed char, signed char) ALLOC_SIZE (1, 2);
void* f_ushrt_1 (unsigned short) ALLOC_SIZE (1);
void* f_ushrt_2 (unsigned short, unsigned short) ALLOC_SIZE (1, 2);
void* f_shrt_1 (signed short) ALLOC_SIZE (1);
void* f_shrt_2 (signed short, signed short) ALLOC_SIZE (1, 2);
void* f_uint_1 (unsigned) ALLOC_SIZE (1);
void* f_uint_2 (unsigned, unsigned) ALLOC_SIZE (1, 2);
void* f_int_1 (int) ALLOC_SIZE (1);
void* f_int_2 (int, int) ALLOC_SIZE (1, 2);
void* f_ulong_1 (unsigned long) ALLOC_SIZE (1);
void* f_ulong_2 (unsigned long, unsigned long) ALLOC_SIZE (1, 2);
void* f_long_1 (long) ALLOC_SIZE (1);
void* f_long_2 (long, long) ALLOC_SIZE (1, 2);
void* f_ullong_1 (unsigned long long) ALLOC_SIZE (1);
void* f_ullong_2 (unsigned long long, unsigned long long) ALLOC_SIZE (1, 2);
void* f_llong_1 (long long) ALLOC_SIZE (1);
void* f_llong_2 (long long, long long) ALLOC_SIZE (1, 2);
void* f_size_1 (size_t) ALLOC_SIZE (1);
void* f_size_2 (size_t, size_t) ALLOC_SIZE (1, 2);
void* f_size_1_nonnull (size_t)
ALLOC_SIZE (1) __attribute__ ((returns_nonnull));
void* f_size_2_nonnull (size_t, size_t)
ALLOC_SIZE (1, 2) __attribute__ ((returns_nonnull));
void sink (void*);
void
test_uchar (unsigned char n)
{
sink (f_uchar_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uchar_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uchar_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_uchar_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_uchar_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uchar_1 (n));
n = 0;
sink (f_uchar_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uchar_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_schar (signed char n)
{
sink (f_schar_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_schar_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_schar_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_schar_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_schar_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_schar_1 (n));
n = 0;
sink (f_schar_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_schar_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_ushrt (unsigned short n)
{
sink (f_ushrt_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ushrt_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ushrt_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_ushrt_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_ushrt_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ushrt_1 (n));
n = 0;
sink (f_ushrt_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ushrt_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_shrt (short n)
{
sink (f_shrt_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_shrt_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_shrt_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_shrt_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_shrt_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_shrt_1 (n));
n = 0;
sink (f_shrt_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_shrt_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_uint (unsigned n)
{
sink (f_uint_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uint_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uint_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_uint_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_uint_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uint_1 (n));
n = 0;
sink (f_uint_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_uint_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_int (int n)
{
sink (f_int_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_int_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_int_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_int_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_int_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_int_1 (n));
n = 0;
sink (f_int_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_int_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_ulong (unsigned long n)
{
sink (f_ulong_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ulong_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ulong_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_ulong_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_ulong_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ulong_1 (n));
n = 0;
sink (f_ulong_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_ulong_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_long (long n)
{
sink (f_long_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_long_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_long_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_long_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_long_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_long_1 (n));
n = 0;
sink (f_long_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_long_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
void
test_size (size_t n)
{
sink (f_size_1 (0)); /* { dg-warning "argument 1 value is zero" } */
sink (f_size_2 (0, 1)); /* { dg-warning "argument 1 value is zero" } */
sink (f_size_2 (1, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_size_2 (n, 0)); /* { dg-warning "argument 2 value is zero" } */
sink (f_size_2 (0, n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_size_1 (n));
n = 0;
sink (f_size_1 (n)); /* { dg-warning "argument 1 value is zero" } */
sink (f_size_2 (1, n)); /* { dg-warning "argument 2 value is zero" } */
}
/* Verify that calls to allocation function decorated with attribute
returns_nonnull don't cause warnings (unlike functions like malloc
that can return null in this case there's nothing to warn about
because a returns_nonnull function guarantees success). */
void
test_size_nonnull (size_t n)
{
sink (f_size_1_nonnull (0));
sink (f_size_2_nonnull (0, 1));
sink (f_size_2_nonnull (1, 0));
sink (f_size_2_nonnull (n, 0));
sink (f_size_2_nonnull (0, n));
sink (f_size_1_nonnull (n));
n = 0;
sink (f_size_1_nonnull (n));
sink (f_size_2_nonnull (1, n));
}
/* Verify that call to plain alloca(0) is not diagnosed. */
void
test_alloca (size_t n)
{
extern void* alloca (size_t);
alloca (0);
}
/* PR c/78284 - warn on malloc with very large arguments
Test exercising the ability of the built-in allocation functions
to detect and diagnose, without optimization, calls that attemnpt
to allocate objects in excess of the number of bytes specified by
-Walloc-larger-than=maximum. */
/* { dg-do compile } */
/* { dg-options "-O0 -Wall -Walloc-size-larger-than=12345" } */
#define MAXOBJSZ 12345
typedef __SIZE_TYPE__ size_t;
void sink (void*);
void test_lit (char *p, char *q)
{
sink (__builtin_aligned_alloc (MAXOBJSZ, 1));
sink (__builtin_aligned_alloc (MAXOBJSZ + 1, 1)); /* { dg-warning "argument 1 value .12346\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_alloca (MAXOBJSZ));
sink (__builtin_alloca (MAXOBJSZ + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_calloc (MAXOBJSZ, 1));
sink (__builtin_calloc (1, MAXOBJSZ));
/* Verify that the signed to unsigned conversion below doesn't cause
a warning. */
sink (__builtin_calloc (p - q, 1));
sink (__builtin_calloc (1, q - p));
sink (__builtin_calloc (p - q, MAXOBJSZ));
sink (__builtin_calloc (MAXOBJSZ, q - p));
sink (__builtin_calloc (MAXOBJSZ / 2, 3)); /* { dg-warning "product .6172\[lu\]* \\* 3\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_calloc (4, MAXOBJSZ / 3)); /* { dg-warning "product .4\[lu\]* \\* 4115\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_malloc (MAXOBJSZ));
sink (__builtin_malloc (MAXOBJSZ + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_realloc (p, MAXOBJSZ));
sink (__builtin_realloc (p, MAXOBJSZ + 4)); /* { dg-warning "argument 2 value .12349\[lu\]*. exceeds maximum object size 12345" } */
}
enum { max = MAXOBJSZ };
void test_cst (char *p, char *q)
{
sink (__builtin_aligned_alloc (max, 1));
sink (__builtin_aligned_alloc (max + 1, 1)); /* { dg-warning "argument 1 value .12346\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_alloca (max));
sink (__builtin_alloca (max + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_calloc (max, 1));
sink (__builtin_calloc (1, max));
/* Verify that the signed to unsigned conversion below doesn't cause
a warning. */
sink (__builtin_calloc (p - q, 1));
sink (__builtin_calloc (1, q - p));
sink (__builtin_calloc (p - q, max));
sink (__builtin_calloc (max, q - p));
sink (__builtin_calloc (max / 2, 3)); /* { dg-warning "product .6172\[lu\]* \\* 3\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_calloc (4, max / 3)); /* { dg-warning "product .4\[lu\]* \\* 4115\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_malloc (max));
sink (__builtin_malloc (max + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_realloc (p, max));
sink (__builtin_realloc (p, max + 4)); /* { dg-warning "argument 2 value .12349\[lu\]*. exceeds maximum object size 12345" } */
}
/* PR c/78284 - warn on malloc with very large arguments
Test exercising the ability of the built-in allocation functions to
detect and diagnose calls that attemnpt to allocate objects in excess
of the maximum specified by -Walloc-size-larger-than=maximum. */
/* { dg-do compile } */
/* { dg-options "-O2 -Wall -Walloc-size-larger-than=12345" } */
#define SIZE_MAX __SIZE_MAX__
#define MAXOBJSZ 12345
typedef __SIZE_TYPE__ size_t;
void sink (void*);
size_t maxobjsize (void)
{
return MAXOBJSZ;
}
void test_var (void *p)
{
size_t max = maxobjsize ();
sink (__builtin_aligned_alloc (max, 1));
sink (__builtin_aligned_alloc (max + 1, 1)); /* { dg-warning "argument 1 value .12346\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_alloca (max));
sink (__builtin_alloca (max + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_calloc (1, max));
sink (__builtin_calloc (max, 1));
sink (__builtin_calloc (max / 2, 3)); /* { dg-warning "product .6172\[lu\]* \\* 3\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_calloc (4, max / 3)); /* { dg-warning "product .4\[lu\]* \\* 4115\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_malloc (max));
sink (__builtin_malloc (max + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */
sink (__builtin_realloc (p, max));
sink (__builtin_realloc (p, max + 4)); /* { dg-warning "argument 2 value .12349\[lu\]*. exceeds maximum object size 12345" } */
}
void test_range (void *p, size_t range)
{
/* Make sure the variable is at least as large as the maximum object
size but also make sure that it's guaranteed not to be too big to
increment (and wrap around). */
size_t max = maxobjsize ();
if (range < max || 2 * max <= range)
range = maxobjsize ();
sink (__builtin_aligned_alloc (range, 1));
sink (__builtin_aligned_alloc (range + 1, 1)); /* { dg-warning "argument 1 range \\\[12346\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size 12345" } */
sink (__builtin_alloca (range));
sink (__builtin_alloca (range + 2)); /* { dg-warning "argument 1 range \\\[12347\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size 12345" } */
sink (__builtin_calloc (range, 1));
sink (__builtin_calloc (1, range));
sink (__builtin_calloc (range / 2, 3)); /* { dg-warning "product .6172\[lu\]* \\* 3\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_calloc (4, range / 3)); /* { dg-warning "product .4\[lu\]* \\* 4115\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */
sink (__builtin_malloc (range));
sink (__builtin_malloc (range + 3)); /* { dg-warning "argument 1 range \\\[12348\[lu\]*, 24692\[lu\]*\\\] exceeds maximum object size 12345" } */
sink (__builtin_realloc (p, range));
sink (__builtin_realloc (p, range + 4)); /* { dg-warning "argument 2 range \\\[12349\[lu\]*, 24693\[lu\]*\\\] exceeds maximum object size 12345" } */
}
/* PR c/78284 - warn on malloc with very large arguments
Test to exercise the interaction of the -Walloca-larger-than,
-Wvla-larger-than, and -Walloc-size-larger-than options. The former
two more specific options override the more general latter option. */
/* { dg-do compile } */
/* { dg-options "-O2 -Walloc-size-larger-than=123 -Walloca-larger-than=234 -Wvla-larger-than=345" } */
#define SIZE_MAX __SIZE_MAX__
typedef __SIZE_TYPE__ size_t;
void sink (void*);
size_t alloc_size_limit (void)
{
return 123;
}
size_t alloca_limit (void)
{
return 234;
}
size_t vla_limit (void)
{
return 345;
}
void test_alloca (void)
{
void *p;
/* No warning should be issued for the following call because the more
permissive alloca limit overrides the stricter alloc_size limit. */
p = __builtin_alloca (alloca_limit ());
sink (p);
p = __builtin_alloca (alloca_limit () + 1); /* { dg-warning "argument to .alloca. is too large" } */
sink (p);
}
void test_vla (void)
{
/* Same as above, no warning should be issued here because the more
permissive VLA limit overrides the stricter alloc_size limit. */
char vla1 [vla_limit ()];
sink (vla1);
char vla2 [vla_limit () + 1]; /* { dg-warning "argument to variable-length array is too large" } */
sink (vla2);
}
void test_malloc (void)
{
void *p;
p = __builtin_malloc (alloc_size_limit ());
sink (p);
p = __builtin_malloc (alloc_size_limit () + 1); /* { dg-warning "argument 1 value .124\[lu\]*. exceeds maximum object size 123" } */
sink (p);
}
/* PR c/78284 - warn on malloc with very large arguments
Test verifying that the built-in allocation functions are declared
with attribute malloc. This means that the pointer they return
can be assumed not to alias any other valid pointer. */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
void sink (void*);
extern int x;
#define TEST(call) \
do { \
p = call; \
x = 123; \
*(int*)p = 456; \
(x == 123) ? (void)0 : __builtin_abort (); \
sink (p); \
} while (0)
void test (void *p, unsigned n)
{
TEST (__builtin_aligned_alloc (n, 8));
TEST (__builtin_alloca (n));
TEST (__builtin_calloc (4, n));
TEST (__builtin_malloc (n));
TEST (__builtin_realloc (p, n + 1));
}
/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
......@@ -10,6 +10,7 @@ int main()
{
void * volatile p;
errno = 0;
/* The malloc call below may cause a -Walloc-size-larger-than warning. */
p = malloc (-1);
if (errno != 0)
do_not_optimize_away ();
......@@ -17,3 +18,4 @@ int main()
}
/* { dg-final { scan-assembler "do_not_optimize_away" } } */
/* { dg-prune-output "exceeds maximum object size" } */
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