PR c/77531 - __attribute__((alloc_size(1,2))) could also warn on multiplication overflow
PR c/78284 - warn on malloc with very large arguments
include/ChangeLog:
* libiberty.h (XALLOCAVEC): Make sure alloca argument is non-zero.
gcc/c-family/ChangeLog:
PR c/77531
PR c/78284
* c.opt (-Walloc-zero, -Walloc-larger-than): New options.
gcc/ChangeLog:
PR c/77531
PR c/78284
* builtin-attrs.def (ATTR_ALLOC_SIZE): New identifier tree.
(ATTR_MALLOC_SIZE_1_NOTHROW_LIST): New attribute list.
(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 (akigned_alloc, alloca, calloc, malloc, realloc):
Add attribute alloc_size.
* calls.h (maybe_warn_alloc_args_overflow): Declare.
* calls.c (alloc_max_size): New function.
(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-larger-than.
gcc/testsuite/ChangeLog:
PR c/77531
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.
@@ -83,6 +83,7 @@ DEF_LIST_INT_INT (5,6)
#undef DEF_LIST_INT_INT
/* Construct trees for identifiers. */
+DEF_ATTR_IDENT (ATTR_ALLOC_SIZE, "alloc_size")
DEF_ATTR_IDENT (ATTR_COLD, "cold")
DEF_ATTR_IDENT (ATTR_CONST, "const")
DEF_ATTR_IDENT (ATTR_FORMAT, "format")
@@ -150,6 +151,23 @@ DEF_ATTR_TREE_LIST (ATTR_SENTINEL_NOTHROW_LEAF_LIST, ATTR_SENTINEL, \
DEF_ATTR_TREE_LIST (ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST, ATTR_CONST,\
ATTR_NULL, ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+/* Allocation functions like alloca and malloc whose first argument
+ specifies the size of the allocated object. */
+DEF_ATTR_TREE_LIST (ATTR_MALLOC_SIZE_1_NOTHROW_LIST, ATTR_ALLOC_SIZE, \
+ ATTR_LIST_1, ATTR_NOTHROW_LIST)
+DEF_ATTR_TREE_LIST (ATTR_MALLOC_SIZE_1_NOTHROW_LEAF_LIST, ATTR_ALLOC_SIZE, \
+ ATTR_LIST_1, ATTR_MALLOC_NOTHROW_LEAF_LIST)
+
+/* Allocation functions like calloc the product of whose first two arguments
+ specifies the size of the allocated object. */
+DEF_ATTR_TREE_LIST (ATTR_MALLOC_SIZE_1_2_NOTHROW_LEAF_LIST, ATTR_ALLOC_SIZE, \
+ ATTR_LIST_1_2, ATTR_MALLOC_NOTHROW_LEAF_LIST)
+
+/* Allocation functions like realloc whose second argument specifies
+ the size of the allocated object. */
+DEF_ATTR_TREE_LIST (ATTR_ALLOC_SIZE_2_NOTHROW_LEAF_LIST, ATTR_ALLOC_SIZE, \
+ ATTR_LIST_2, ATTR_NOTHROW_LEAF_LIST)
+
/* Functions whose pointer parameter(s) are all nonnull. */
DEF_ATTR_TREE_LIST (ATTR_NONNULL_LIST, ATTR_NONNULL, ATTR_NULL, ATTR_NULL)
/* Functions whose first parameter is a nonnull pointer. */
@@ -4327,12 +4327,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));
@@ -4340,6 +4340,10 @@ expand_builtin_alloca (tree exp, bool cannot_accumulate)
if (!valid_arglist)
return NULL_RTX;
+ 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));
@@ -284,7 +284,7 @@ DEF_C99_BUILTIN (BUILT_IN_ACOSH, "acosh", BT_FN_DOUBLE_DOUBLE, ATTR_MATHF
DEF_C99_BUILTIN (BUILT_IN_ACOSHF, "acoshf", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
DEF_C99_BUILTIN (BUILT_IN_ACOSHL, "acoshl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
DEF_C99_C90RES_BUILTIN (BUILT_IN_ACOSL, "acosl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
-DEF_C11_BUILTIN (BUILT_IN_ALIGNED_ALLOC, "aligned_alloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_NOTHROW_LIST)
+DEF_C11_BUILTIN (BUILT_IN_ALIGNED_ALLOC, "aligned_alloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_SIZE_1_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_ASIN, "asin", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
DEF_C99_C90RES_BUILTIN (BUILT_IN_ASINF, "asinf", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
DEF_C99_BUILTIN (BUILT_IN_ASINH, "asinh", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING)
@@ -764,7 +764,7 @@ DEF_GCC_BUILTIN (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_
DEF_LIB_BUILTIN (BUILT_IN_ABORT, "abort", BT_FN_VOID, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
DEF_LIB_BUILTIN (BUILT_IN_ABS, "abs", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_AGGREGATE_INCOMING_ADDRESS, "aggregate_incoming_address", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
-DEF_EXT_LIB_BUILTIN (BUILT_IN_ALLOCA, "alloca", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
+DEF_EXT_LIB_BUILTIN (BUILT_IN_ALLOCA, "alloca", BT_FN_PTR_SIZE, ATTR_MALLOC_SIZE_1_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_APPLY, "apply", BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_APPLY_ARGS, "apply_args", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_BSWAP16, "bswap16", BT_FN_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -772,7 +772,7 @@ DEF_GCC_BUILTIN (BUILT_IN_BSWAP32, "bswap32", BT_FN_UINT32_UINT32, ATTR_C
DEF_GCC_BUILTIN (BUILT_IN_BSWAP64, "bswap64", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_CLEAR_CACHE, "__clear_cache", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)
/* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed. */
-DEF_LIB_BUILTIN (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
+DEF_LIB_BUILTIN (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_SIZE_1_2_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLASSIFY_TYPE, "classify_type", BT_FN_INT_VAR, ATTR_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLZ, "clz", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLZIMAX, "clzimax", BT_FN_INT_UINTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -848,7 +848,7 @@ DEF_LIB_BUILTIN (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHR
DEF_C99_BUILTIN (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LIST)
/* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is changed. */
-DEF_LIB_BUILTIN (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
+DEF_LIB_BUILTIN (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, ATTR_MALLOC_SIZE_1_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_PARITY, "parity", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_PARITYIMAX, "parityimax", BT_FN_INT_UINTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -860,7 +860,7 @@ DEF_GCC_BUILTIN (BUILT_IN_POPCOUNTL, "popcountl", BT_FN_INT_ULONG, ATTR_C
DEF_GCC_BUILTIN (BUILT_IN_POPCOUNTLL, "popcountll", BT_FN_INT_ULONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_POSIX_MEMALIGN, "posix_memalign", BT_FN_INT_PTRPTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
DEF_GCC_BUILTIN (BUILT_IN_PREFETCH, "prefetch", BT_FN_VOID_CONST_PTR_VAR, ATTR_NOVOPS_LEAF_LIST)
-DEF_LIB_BUILTIN (BUILT_IN_REALLOC, "realloc", BT_FN_PTR_PTR_SIZE, ATTR_NOTHROW_LEAF_LIST)
+DEF_LIB_BUILTIN (BUILT_IN_REALLOC, "realloc", BT_FN_PTR_PTR_SIZE, ATTR_ALLOC_SIZE_2_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_RETURN, "return", BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_RETURN_ADDRESS, "return_address", BT_FN_PTR_UINT, ATTR_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_SAVEREGS, "saveregs", BT_FN_PTR_VAR, ATTR_NULL)
@@ -299,6 +299,15 @@ Walloca
C ObjC C++ ObjC++ Var(warn_alloca) Warning
Warn on any use of alloca.
+Walloc-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloc_limit) Warning Joined
+-Walloc-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 EnabledBy(Wextra)
+-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,239 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
}
}
+static tree alloc_object_size_limit;
+
+/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-larger-than=limit
+ 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_limit ? strtoull (warn_alloc_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;
+}
+
+/* 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-larger-than= or SIZE_MAX / 2. */
+ tree maxobjsize = alloc_max_size ();
+
+ location_t loc = tree_nonartificial_location (exp); // 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_larger_than_,
+ "argument %i value %qE is negative",
+ idx[i] + 1, args[i]);
+ }
+ else if (integer_zerop (args[i]))
+ {
+ 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_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)
+ {
+ argrange[i][0] = wide_int_to_tree (type, max + 1);
+ argrange[i][1] = wide_int_to_tree (type, min - 1);
+
+ /* 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_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_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_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]))
+ {
+ /* 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_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_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)
+ {
+ if (EXPR_HAS_LOCATION (fn))
+ inform (DECL_SOURCE_LOCATION (fn),
+ "in a call to allocation function %qD declared here", fn);
+ else
+ inform (loc,
+ "in a call to built-in allocation function %qD", fn);
+ }
+}
+
/* Issue an error if CALL_EXPR was flagged as requiring
tall-call optimization. */
@@ -1359,6 +1594,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 +1848,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
@@ -256,6 +256,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-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
@@ -4990,6 +4991,24 @@ 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 relying on it may
+result in subtle portability bugs and should be avoided. This option is
+enabled with @option{-Wextra}
+
+@item -Walloc-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}.
+@xref{Function Attributes}.
+
@item -Walloca
@opindex Wno-alloca
@opindex Walloca
new file mode 100644
@@ -0,0 +1,447 @@
+/* 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. */
+/* { 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 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);
+
+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)
+{
+ 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 (n, 0));
+ sink (f_uchar_2 (1, n));
+ sink (f_uchar_2 (n, 1));
+ sink (f_uchar_2 (max, n));
+ sink (f_uchar_2 (n, max));
+ sink (f_uchar_2 (n, n));
+
+ 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 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, max / 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, max / 2)));
+
+ sink (f_size_2 (n, n));
+ sink (f_size_2 (n, max / 2));
+ sink (f_size_2 (max / 2, n));
+
+ sink (f_size_2 (UR (0, 1), max)); /* { dg-warning "argument 2 value .\[0-9\]+\[lu\]*. exceeds maximum object size " } */
+ sink (f_size_2 (UR (0, 1), max / 2));
+ sink (f_size_2 (UR (0, max / 2), max / 2));
+
+ sink (f_size_2 (UR (max / 2 + 1, max / 2 + 2), n)); /* { dg-warning "argument 1 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
+ sink (f_size_2 (n, UR (max / 2 + 1, max / 2 + 2))); /* { dg-warning "argument 2 range \\\[\[0-9\]+\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size " } */
+ sink (f_size_2 (UR (max / 2 + 1, max), UR (max / 2 + 1, 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 } */
+
+}
new file mode 100644
@@ -0,0 +1,190 @@
+/* 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. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wall -Walloc-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 } */
+
+}
new file mode 100644
@@ -0,0 +1,199 @@
+/* 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 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" } */
+}
new file mode 100644
@@ -0,0 +1,45 @@
+/* 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-larger-than=12345" } */
+
+#define MAXOBJSZ 12345
+
+typedef __SIZE_TYPE__ size_t;
+
+void sink (void*);
+
+
+void test_lit (void *p)
+{
+ sink (__builtin_aligned_alloc (MAXOBJSZ + 1, 1)); /* { dg-warning "argument 1 value .12346\[lu\]*. exceeds maximum object size 12345" } */
+
+ sink (__builtin_alloca (MAXOBJSZ + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */
+
+ 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 + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */
+
+ sink (__builtin_realloc (p, MAXOBJSZ + 4)); /* { dg-warning "argument 2 value .12349\[lu\]*. exceeds maximum object size 12345" } */
+}
+
+
+enum { max = MAXOBJSZ };
+
+void test_cst (void *p)
+{
+ sink (__builtin_aligned_alloc (max + 1, 1)); /* { dg-warning "argument 1 value .12346\[lu\]*. exceeds maximum object size 12345" } */
+
+ sink (__builtin_alloca (max + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */
+
+ 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 + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */
+
+ sink (__builtin_realloc (p, max + 4)); /* { dg-warning "argument 2 value .12349\[lu\]*. exceeds maximum object size 12345" } */
+}
new file mode 100644
@@ -0,0 +1,58 @@
+/* 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-larger-than=maximum. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wall -Walloc-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, 1)); /* { dg-warning "argument 1 value .12346\[lu\]*. exceeds maximum object size 12345" } */
+
+ sink (__builtin_alloca (max + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */
+
+ 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 + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */
+
+ 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, 1)); /* { dg-warning "argument 1 range \\\[12346\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size 12345" } */
+
+ sink (__builtin_alloca (range + 2)); /* { dg-warning "argument 1 range \\\[12347\[lu\]*, \[0-9\]+\[lu\]*\\\] exceeds maximum object size 12345" } */
+
+ 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 + 3)); /* { dg-warning "argument 1 range \\\[12348\[lu\]*, 24692\[lu\]*\\\] exceeds maximum object size 12345" } */
+
+ sink (__builtin_realloc (p, range + 4)); /* { dg-warning "argument 2 range \\\[12349\[lu\]*, 24693\[lu\]*\\\] exceeds maximum object size 12345" } */
+}
@@ -353,7 +353,7 @@ extern unsigned int xcrc32 (const unsigned char *, int, unsigned int);
/* Array allocators. */
-#define XALLOCAVEC(T, N) ((T *) alloca (sizeof (T) * (N)))
+#define XALLOCAVEC(T, N) ((T *) alloca ((sizeof (T) * (N)) | 1))
#define XNEWVEC(T, N) ((T *) xmalloc (sizeof (T) * (N)))
#define XCNEWVEC(T, N) ((T *) xcalloc ((N), sizeof (T)))
#define XDUPVEC(T, P, N) ((T *) xmemdup ((P), sizeof (T) * (N), sizeof (T) * (N)))