PR tree-optimization/78775 - [7 Regression] ICE in maybe_warn_alloc_args_overflow
authorMartin Sebor <msebor@redhat.com>
Tue, 10 Jan 2017 21:02:07 +0000 (21:02 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Tue, 10 Jan 2017 21:02:07 +0000 (14:02 -0700)
gcc/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

From-SVN: r244290

12 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/calls.c
gcc/calls.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/attr-alloc_size-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-alloc_size-11.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-alloc_size-4.c
gcc/testsuite/gcc.dg/builtin-stringop-chk-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr78775.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr78973-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr78973.c [new file with mode: 0644]

index a60c742..d0c53d0 100644 (file)
@@ -1,3 +1,13 @@
+2017-01-10  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/78775
+       * builtins.c (get_size_range): Move...
+       * calls.c: ...to here.
+       (alloc_max_size): Accept zero argument.
+       (operand_signed_p): Remove.
+       (maybe_warn_alloc_args_overflow): Call get_size_range.
+       * calls.h (get_size_range): Declare.
+
 2017-01-10  Joe Seymour  <joe.s@somniumtech.com>
 
        * config/msp430/driver-msp430.c (msp430_mcu_data): Sync with data
index 5b76dfd..bf68e31 100644 (file)
@@ -3031,42 +3031,6 @@ expand_builtin_memcpy_args (tree dest, tree src, tree len, rtx target, tree exp)
   return dest_addr;
 }
 
-/* Fill the 2-element RANGE array with the minimum and maximum values
-   EXP is known to have and return true, otherwise null and return
-   false.  */
-
-static bool
-get_size_range (tree exp, tree range[2])
-{
-  if (tree_fits_uhwi_p (exp))
-    {
-      range[0] = range[1] = exp;
-      return true;
-    }
-
-  if (TREE_CODE (exp) == SSA_NAME)
-    {
-      wide_int min, max;
-      enum value_range_type range_type = get_range_info (exp, &min, &max);
-
-      if (range_type == VR_RANGE)
-       {
-         /* Interpret the bound in the variable's type.  */
-         range[0] = wide_int_to_tree (TREE_TYPE (exp), min);
-         range[1] = wide_int_to_tree (TREE_TYPE (exp), max);
-         return true;
-       }
-      else if (range_type == VR_ANTI_RANGE)
-       {
-         /* FIXME: Handle anti-ranges.  */
-       }
-    }
-
-  range[0] = NULL_TREE;
-  range[1] = NULL_TREE;
-  return false;
-}
-
 /* Try to verify that the sizes and lengths of the arguments to a string
    manipulation function given by EXP are within valid bounds and that
    the operation does not lead to buffer overflow.  Arguments other than
index b7bbec5..7b45b9a 100644 (file)
@@ -1197,92 +1197,144 @@ alloc_max_size (void)
     {
       alloc_object_size_limit = TYPE_MAX_VALUE (ssizetype);
 
-      unsigned HOST_WIDE_INT unit = 1;
-
-      char *end;
-      errno = 0;
-      unsigned HOST_WIDE_INT limit
-       = warn_alloc_size_limit ? strtoull (warn_alloc_size_limit, &end, 10) : 0;
-
-      if (limit && !errno)
+      if (warn_alloc_size_limit)
        {
-         if (end && *end)
+         char *end = NULL;
+         errno = 0;
+         unsigned HOST_WIDE_INT unit = 1;
+         unsigned HOST_WIDE_INT limit
+           = strtoull (warn_alloc_size_limit, &end, 10);
+
+         if (!errno)
            {
-             /* 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 (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);
+             if (unit)
+               alloc_object_size_limit
+                 = build_int_cst (ssizetype, limit * unit);
+           }
        }
     }
   return alloc_object_size_limit;
 }
 
-/* Return true if the type of OP is signed, looking through any casts
-   to an unsigned type.  */
+/* Return true when EXP's range can be determined and set RANGE[] to it
+   after adjusting it if necessary to make EXP a valid size argument to
+   an allocation function declared with attribute alloc_size (whose
+   argument may be signed), or to a string manipulation function like
+   memset.  */
 
-static bool
-operand_signed_p (tree op)
+bool
+get_size_range (tree exp, tree range[2])
 {
-  if (TREE_CODE (op) == SSA_NAME)
+  if (tree_fits_uhwi_p (exp))
     {
-      gimple *def = SSA_NAME_DEF_STMT (op);
-      if (is_gimple_assign (def))
-       {
-         /* In an assignment involving a cast, ignore the type
-            of the cast and consider the type of its  operand.  */
-         tree_code code = gimple_assign_rhs_code (def);
-         if (code == NOP_EXPR)
-           op = gimple_assign_rhs1 (def);
-       }
-      else if (gimple_code (def) == GIMPLE_PHI)
+      /* EXP is a constant.  */
+      range[0] = range[1] = exp;
+      return true;
+    }
+
+  wide_int min, max;
+  enum value_range_type range_type
+    = (TREE_CODE (exp) == SSA_NAME
+       ? get_range_info (exp, &min, &max) : VR_VARYING);
+
+  if (range_type == VR_VARYING)
+    {
+      /* No range information available.  */
+      range[0] = NULL_TREE;
+      range[1] = NULL_TREE;
+      return false;
+    }
+
+  tree exptype = TREE_TYPE (exp);
+  unsigned expprec = TYPE_PRECISION (exptype);
+  wide_int wzero = wi::zero (expprec);
+  wide_int wmaxval = wide_int (TYPE_MAX_VALUE (exptype));
+
+  bool signed_p = !TYPE_UNSIGNED (exptype);
+
+  if (range_type == VR_ANTI_RANGE)
+    {
+      if (signed_p)
        {
-         /* 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)
+         if (wi::les_p (max, wzero))
            {
-             tree op = gimple_phi_arg_def (def, i);
-             if (TREE_CODE (op) != INTEGER_CST
-                 && !operand_signed_p (op))
-               return false;
+             /* EXP is not in a strictly negative range.  That means
+                it must be in some (not necessarily strictly) positive
+                range which includes zero.  Since in signed to unsigned
+                conversions negative values end up converted to large
+                positive values, and otherwise they are not valid sizes,
+                the resulting range is in both cases [0, TYPE_MAX].  */
+             min = wzero;
+             max = wmaxval;
            }
-
-         return true;
+         else if (wi::les_p (min - 1, wzero))
+           {
+             /* EXP is not in a negative-positive range.  That means EXP
+                is either negative, or greater than max.  Since negative
+                sizes are invalid make the range [MAX + 1, TYPE_MAX].  */
+             min = max + 1;
+             max = wmaxval;
+           }
+         else
+           {
+             max = min - 1;
+             min = wzero;
+           }
+       }
+      else if (wi::eq_p (wzero, min - 1))
+       {
+         /* EXP is unsigned and not in the range [1, MAX].  That means
+            it's either zero or greater than MAX.  Even though 0 would
+            normally be detected by -Walloc-zero set the range to
+            [MAX, TYPE_MAX] so that when MAX is greater than the limit
+            the whole range is diagnosed.  */
+         min = max + 1;
+         max = wmaxval;
+       }
+      else
+       {
+         max = min - 1;
+         min = wzero;
        }
     }
 
-  return !TYPE_UNSIGNED (TREE_TYPE (op));
+  range[0] = wide_int_to_tree (exptype, min);
+  range[1] = wide_int_to_tree (exptype, max);
+
+  return true;
 }
 
 /* Diagnose a call EXP to function FN decorated with attribute alloc_size
@@ -1316,8 +1368,8 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
          if (tree_int_cst_lt (args[i], integer_zero_node))
            {
              warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "argument %i value %qE is negative",
-                                  idx[i] + 1, args[i]);
+                                  "%Kargument %i value %qE is negative",
+                                  exp, idx[i] + 1, args[i]);
            }
          else if (integer_zerop (args[i]))
            {
@@ -1334,8 +1386,8 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
                      && !lookup_attribute ("returns_nonnull",
                                            TYPE_ATTRIBUTES (TREE_TYPE (fn)))))
                warned = warning_at (loc, OPT_Walloc_zero,
-                                    "argument %i value is zero",
-                                    idx[i] + 1);
+                                    "%Kargument %i value is zero",
+                                    exp, idx[i] + 1);
            }
          else if (tree_int_cst_lt (maxobjsize, args[i]))
            {
@@ -1351,79 +1403,31 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
                continue;
 
              warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "argument %i value %qE exceeds "
+                                  "%Kargument %i value %qE exceeds "
                                   "maximum object size %E",
-                                  idx[i] + 1, args[i], maxobjsize);
+                                  exp, idx[i] + 1, args[i], maxobjsize);
            }
        }
-      else if (TREE_CODE (args[i]) == SSA_NAME)
+      else if (TREE_CODE (args[i]) == SSA_NAME
+              && get_size_range (args[i], argrange[i]))
        {
-         tree type = TREE_TYPE (args[i]);
-
-         wide_int min, max;
-         value_range_type range_type = get_range_info (args[i], &min, &max);
-         if (range_type == VR_RANGE)
-           {
-             argrange[i][0] = wide_int_to_tree (type, min);
-             argrange[i][1] = wide_int_to_tree (type, max);
-           }
-         else if (range_type == VR_ANTI_RANGE)
-           {
-             /* For an anti-range, if the type of the formal argument
-                is unsigned and the bounds of the range are of opposite
-                signs when interpreted as signed, check to see if the
-                type of the actual argument is signed.  If so, the lower
-                bound must be taken to be zero (rather than a large
-                positive value corresonding to the actual lower bound
-                interpreted as unsigned) and there is nothing else that
-                can be inferred from it.  */
-             --min;
-             ++max;
-             wide_int zero = wi::uhwi (0, TYPE_PRECISION (type));
-             if (TYPE_UNSIGNED (type)
-                 && wi::lts_p (zero, min) && wi::lts_p (max, zero)
-                 && operand_signed_p (args[i]))
-               continue;
-
-             argrange[i][0] = wide_int_to_tree (type, max);
-             argrange[i][1] = wide_int_to_tree (type, min);
-
-             /* Verify that the anti-range doesn't make all arguments
-                invalid (treat the anti-range ~[0, 0] as invalid).  */
-             if (tree_int_cst_lt (maxobjsize, argrange[i][0])
-                 && tree_int_cst_le (argrange[i][1], integer_zero_node))
-               {
-                 warned
-                   = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                 (TYPE_UNSIGNED (type)
-                                  ? G_("argument %i range [%E, %E] exceeds "
-                                       "maximum object size %E")
-                                  : G_("argument %i range [%E, %E] is both "
-                                       "negative and exceeds maximum object "
-                                       "size %E")),
-                                 idx[i] + 1, argrange[i][0],
-                                 argrange[i][1], maxobjsize);
-               }
-             continue;
-           }
-         else
-           continue;
-
          /* Verify that the argument's range is not negative (including
             upper bound of zero).  */
          if (tree_int_cst_lt (argrange[i][0], integer_zero_node)
              && tree_int_cst_le (argrange[i][1], integer_zero_node))
            {
              warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "argument %i range [%E, %E] is negative",
-                                  idx[i] + 1, argrange[i][0], argrange[i][1]);
+                                  "%Kargument %i range [%E, %E] is negative",
+                                  exp, idx[i] + 1,
+                                  argrange[i][0], argrange[i][1]);
            }
          else if (tree_int_cst_lt (maxobjsize, argrange[i][0]))
            {
              warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "argument %i range [%E, %E] exceeds "
+                                  "%Kargument %i range [%E, %E] exceeds "
                                   "maximum object size %E",
-                                  idx[i] + 1, argrange[i][0], argrange[i][1],
+                                  exp, idx[i] + 1,
+                                  argrange[i][0], argrange[i][1],
                                   maxobjsize);
            }
        }
@@ -1450,15 +1454,15 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
 
       if (vflow)
        warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                            "product %<%E * %E%> of arguments %i and %i "
+                            "%Kproduct %<%E * %E%> of arguments %i and %i "
                             "exceeds %<SIZE_MAX%>",
-                            argrange[0][0], argrange[1][0],
+                            exp, argrange[0][0], argrange[1][0],
                             idx[0] + 1, idx[1] + 1);
       else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod))
        warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                            "product %<%E * %E%> of arguments %i and %i "
+                            "%Kproduct %<%E * %E%> of arguments %i and %i "
                             "exceeds maximum object size %E",
-                            argrange[0][0], argrange[1][0],
+                            exp, argrange[0][0], argrange[1][0],
                             idx[0] + 1, idx[1] + 1,
                             maxobjsize);
 
index e87fbda..df5817f 100644 (file)
@@ -38,5 +38,6 @@ extern bool pass_by_reference (CUMULATIVE_ARGS *, machine_mode,
 extern bool reference_callee_copied (CUMULATIVE_ARGS *, machine_mode,
                                     tree, bool);
 extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]);
+extern bool get_size_range (tree, tree[2]);
 
 #endif // GCC_CALLS_H
index 009d32d..f8cba42 100644 (file)
@@ -1,3 +1,14 @@
+2017-01-10  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/78775
+       * gcc.dg/attr-alloc_size-4.c: Add test cases.
+       * gcc.dg/attr-alloc_size-10.c: New test.
+       * gcc.dg/attr-alloc_size-11.c: New test.
+       * gcc.dg/builtin-stringop-chk-7.c: New test.
+       * gcc.dg/pr78775.c: New test.
+       * gcc.dg/pr78973-2.c: New test.
+       * gcc.dg/pr78973.c: New test.
+
 2017-01-10  Jeff Law  <law@redhat.com>
 
        PR tree-optimization/77766
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-10.c b/gcc/testsuite/gcc.dg/attr-alloc_size-10.c
new file mode 100644 (file)
index 0000000..d7a0a98
--- /dev/null
@@ -0,0 +1,142 @@
+/* Verify that -Walloc-size-greater-than doesn't cause false positives
+   for anti-ranges.  Note that not all of the statements used to create
+   anti-ranges below result in the argument being represented as an anti
+   range.
+
+   { dg-do compile }
+   { dg-options "-O2 -Walloc-size-larger-than=12" } */
+
+#define SCHAR_MAX __SCHAR_MAX__
+#define SCHAR_MIN (-SCHAR_MAX - 1)
+#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
+
+#define SHRT_MAX  __SHRT_MAX__
+#define SHRT_MIN  (-SHRT_MAX - 1)
+#define USHRT_MAX (SHRT_MAX * 2 + 1)
+
+#define INT_MAX   __INT_MAX__
+#define INT_MIN   (-INT_MAX - 1)
+#define UINT_MAX  (INT_MAX * 2U + 1)
+
+#define LONG_MAX __LONG_MAX__
+#define LONG_MIN (-LONG_MAX - 1)
+#define ULONG_MAX (LONG_MAX * 2LU + 1)
+
+#define PTRDIFF_MAX __PTRDIFF_MAX__
+#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
+#define SIZE_MAX    __SIZE_MAX__
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__    size_t;
+
+#define CONCAT(a, b)  a ## b
+#define CAT(a, b)     CONCAT (a, b)
+
+/* Macro to generate a unique function to test the anti-range
+   ~[MIN, MAX] for type T.  */
+#define TEST(T, min, max)                                      \
+  void* CAT (test_anti_range_, __LINE__)(T n)                  \
+  {                                                            \
+    extern void* CAT (alloc_anti_range_, __LINE__)(T)          \
+      __attribute__ ((alloc_size (1)));                                \
+    if (min <= n && n <= max)                                  \
+      n = min - 1;                                             \
+    return CAT (alloc_anti_range_, __LINE__)(n);               \
+  } typedef void dummy   /* Require a semicolon.  */
+
+
+/* Verify the anti-range ~[TYPE_MAX - 1, TYPE_MAX - 1].  */
+TEST (signed char, SCHAR_MAX - 1, SCHAR_MAX - 1);
+TEST (unsigned char, UCHAR_MAX - 1, UCHAR_MAX - 1);
+TEST (short, SHRT_MAX - 1, SHRT_MAX - 1);
+TEST (unsigned short, USHRT_MAX - 1, USHRT_MAX - 1);
+TEST (int, INT_MAX - 1, INT_MAX - 1);
+TEST (unsigned, UINT_MAX - 1, UINT_MAX - 1);
+TEST (long, LONG_MAX - 1, LONG_MAX - 1);
+TEST (unsigned long, ULONG_MAX - 1, ULONG_MAX - 1);
+TEST (ptrdiff_t, PTRDIFF_MAX - 1, PTRDIFF_MAX - 1);
+TEST (size_t, SIZE_MAX - 1, SIZE_MAX - 1);
+
+/* Verify ~[0, 0].  */
+TEST (signed char, 0, 0);
+TEST (unsigned char, 0, 0);
+TEST (short, 0, 0);
+TEST (unsigned short, 0, 0);
+TEST (int, 0, 0);
+TEST (unsigned, 0, 0);
+TEST (long, 0, 0);
+TEST (unsigned long, 0, 0);
+TEST (ptrdiff_t, 0, 0);
+TEST (size_t, 0, 0);
+
+/* Verify ~[1, 1].  */
+TEST (signed char, 1, 1);
+TEST (unsigned char, 1, 1);
+TEST (short, 1, 1);
+TEST (unsigned short, 1, 1);
+TEST (int, 1, 1);
+TEST (unsigned, 1, 1);
+TEST (long, 1, 1);
+TEST (unsigned long, 1, 1);
+TEST (ptrdiff_t, 1, 1);
+TEST (size_t, 1, 1);
+
+
+/* Verify ~[TYPE_MAX - 2, TYPE_MAX - 1].  */
+TEST (signed char, SCHAR_MAX - 2, SCHAR_MAX - 1);
+TEST (unsigned char, UCHAR_MAX - 2, UCHAR_MAX - 1);
+TEST (short, SHRT_MAX - 2, SHRT_MAX - 1);
+TEST (unsigned short, USHRT_MAX - 2, USHRT_MAX - 1);
+TEST (int, INT_MAX - 2, INT_MAX - 1);
+TEST (unsigned, UINT_MAX - 2, UINT_MAX - 1);
+TEST (long, LONG_MAX - 2, LONG_MAX - 1);
+TEST (unsigned long, ULONG_MAX - 2, ULONG_MAX - 1);
+TEST (ptrdiff_t, PTRDIFF_MAX - 2, PTRDIFF_MAX - 1);
+TEST (size_t, SIZE_MAX - 2, SIZE_MAX - 1);
+
+/* Verify ~[0, 2].  */
+TEST (signed char, 0, 2);
+TEST (unsigned char, 0, 2);
+TEST (short, 0, 2);
+TEST (unsigned short, 0, 2);
+TEST (int, 0, 2);
+TEST (unsigned int, 0, 2);
+TEST (long, 0, 2);
+TEST (unsigned long, 0, 2);
+TEST (ptrdiff_t, 0, 2);
+TEST (size_t, 0, 2);
+
+/* Verify the signed anti-range ~[TYPE_MIN - 2, -1].  */
+TEST (signed char, SCHAR_MIN + 2, -1);
+TEST (short, SHRT_MIN + 2, -1);
+TEST (int, INT_MIN + 2, -1);
+TEST (long, LONG_MIN + 2, -1);
+TEST (ptrdiff_t, PTRDIFF_MIN + 2, -1);
+
+/* Verify the signed anti-range ~[TYPE_MIN - 2, 0].  */
+TEST (signed char, SCHAR_MIN + 2, 0);
+TEST (short, SHRT_MIN + 2, 0);
+TEST (int, INT_MIN + 2, 0);
+TEST (long, LONG_MIN + 2, 0);
+TEST (ptrdiff_t, PTRDIFF_MIN + 2, 0);
+
+/* Verify the signed anti-range ~[TYPE_MIN - 2, 1].  */
+TEST (signed char, SCHAR_MIN + 2, 1);
+TEST (short, SHRT_MIN + 2, 1);
+TEST (int, INT_MIN + 2, 1);
+TEST (long, LONG_MIN + 2, 1);
+TEST (ptrdiff_t, PTRDIFF_MIN + 2, 1);
+
+/* Verify the signed anti-range ~[TYPE_MIN - 2, 2].  */
+TEST (signed char, SCHAR_MIN + 2, 2);
+TEST (short, SHRT_MIN + 2, 2);
+TEST (int, INT_MIN + 2, 2);
+TEST (long, LONG_MIN + 2, 2);
+TEST (ptrdiff_t, PTRDIFF_MIN + 2, 2);
+
+/* Verify the signed anti-range ~[-1, 2].  */
+TEST (signed char, -1, 2);
+TEST (short, -1, 2);
+TEST (int, -1, 2);
+TEST (long, -1, 2);
+TEST (ptrdiff_t, 01, 2);
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-11.c b/gcc/testsuite/gcc.dg/attr-alloc_size-11.c
new file mode 100644 (file)
index 0000000..fac8b18
--- /dev/null
@@ -0,0 +1,69 @@
+/* Verify that -Walloc-size-greater-than doesn't cause false positives
+   for anti-ranges.  Note that not all of the statements below result
+   in the argument being represented as an anti-range.
+
+   { dg-do compile }
+   { dg-options "-O2 -Walloc-size-larger-than=12 -ftrack-macro-expansion=0" } */
+
+#define SCHAR_MAX __SCHAR_MAX__
+#define SCHAR_MIN (-SCHAR_MAX - 1)
+#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
+
+#define SHRT_MAX  __SHRT_MAX__
+#define SHRT_MIN  (-SHRT_MAX - 1)
+#define USHRT_MAX (SHRT_MAX * 2 + 1)
+
+#define INT_MAX   __INT_MAX__
+#define INT_MIN   (-INT_MAX - 1)
+#define UINT_MAX  (INT_MAX * 2U + 1)
+
+#define LONG_MAX __LONG_MAX__
+#define LONG_MIN (-LONG_MAX - 1)
+#define ULONG_MAX (LONG_MAX * 2LU + 1)
+
+#define PTRDIFF_MAX __PTRDIFF_MAX__
+#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
+#define SIZE_MAX    __SIZE_MAX__
+
+#define ALLOC_MAX   12
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__    size_t;
+
+#define CONCAT(a, b)  a ## b
+#define CAT(a, b)     CONCAT (a, b)
+
+/* Macro to generate a unique function to test the anti-range
+   ~[MIN, MAX] for type T.  */
+#define TEST(T, min, max)                                      \
+  void* CAT (test_anti_range_, __LINE__)(T n)                  \
+  {                                                            \
+    extern void* CAT (alloc_anti_range_, __LINE__)(T)          \
+      __attribute__ ((alloc_size (1)));                                \
+    if (min <= n && n <= max)                                  \
+      n = min - 1;                                             \
+    return CAT (alloc_anti_range_, __LINE__)(n);               \
+  } typedef void dummy   /* Require a semicolon.  */
+
+/* The following tests fail because of missing range information.  */
+TEST (signed char, SCHAR_MIN + 2, ALLOC_MAX);   /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for signed char" { xfail *-*-* } } */
+TEST (short, SHRT_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for short" { xfail *-*-* } } */
+
+TEST (int, INT_MIN + 2, ALLOC_MAX);    /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (int, -3, ALLOC_MAX);             /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (int, -2, ALLOC_MAX);             /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (int, -1, ALLOC_MAX);             /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (int,  0, ALLOC_MAX);             /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (int,  1, ALLOC_MAX);             /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (int,  1, INT_MAX - 1);           /* { dg-warning "argument 1 range \\\[\[0-9\]+, \[0-9\]+\\\] exceeds maximum object size 12" } */
+
+/* The following two aren't necessarily anti-ranges.  */
+TEST (int,  1, INT_MAX);               /* { dg-warning "argument 1 range \\\[-\[0-9\]+, 0\\\] is negative" } */
+TEST (int,  0, INT_MAX);               /* { dg-warning "argument 1 range \\\[-\[0-9\]+, -1\\\] is negative" } */
+
+TEST (long, LONG_MIN + 2, ALLOC_MAX);  /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (ptrdiff_t, PTRDIFF_MIN + 2, ALLOC_MAX);  /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+
+TEST (unsigned, 0, ALLOC_MAX);         /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (unsigned long, 0, ALLOC_MAX);    /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
+TEST (size_t, 0, ALLOC_MAX);           /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
index 6b70a85..5ce593e 100644 (file)
@@ -128,15 +128,22 @@ test_int_range (int n)
 
   sink (f_int_1 (SR (min, 1234)));
   sink (f_int_1 (SR (-2, -1)));   /* { dg-warning "argument 1 range \\\[-2, -1\\\] is negative" } */
+
   sink (f_int_1 (SR (1235, 2345)));  /* { dg-warning "argument 1 range \\\[1235, 2345\\\] exceeds maximum object size 1234" } */
   sink (f_int_1 (SR (max - 1, max)));   /* { dg-warning "argument 1 range \\\[\[0-9\]+, \[0-9\]+\\\] exceeds maximum object size 1234" } */
 
   sink (f_int_1 (SAR (-1, 1)));
   sink (f_int_1 (SAR (-2, 12)));
   sink (f_int_1 (SAR (-3, 123)));
-  sink (f_int_1 (SAR (-4, 1234)));   /* { dg-warning "argument 1 range \\\[1235, -5\\\] is both negative and exceeds maximum object size 1234" } */
+  sink (f_int_1 (SAR (-4, 1234)));   /* { dg-warning "argument 1 range \\\[1235, \[0-9\]+\\\] exceeds maximum object size 1234" } */
   sink (f_int_1 (SAR (min + 1, 1233)));
-  sink (f_int_1 (SAR (min + 2, 1235)));   /* { dg-warning "argument 1 range \\\[1236, -\[0-9\]+\\\] is both negative and exceeds maximum object size 1234" } */
+  sink (f_int_1 (SAR (min + 2, 1235)));   /* { dg-warning "argument 1 range \\\[1236, \[0-9\]+\\\] exceeds maximum object size 1234" } */
+  sink (f_int_1 (SAR (0, max)));   /* { dg-warning "argument 1 range \\\[-\[0-9\]*, -1\\\] is negative" } */
+  /* The range below includes zero which would be diagnosed by
+     -Walloc-size-zero but since all other values are negative it
+     is diagnosed by -Walloc-size-larger-than.  */
+  sink (f_int_1 (SAR (1, max)));   /* { dg-warning "argument 1 range \\\[-\[0-9\]*, 0\\\] is negative" } */
+  sink (f_int_1 (SAR (2, max)));
 }
 
 void
diff --git a/gcc/testsuite/gcc.dg/builtin-stringop-chk-7.c b/gcc/testsuite/gcc.dg/builtin-stringop-chk-7.c
new file mode 100644 (file)
index 0000000..173e4ff
--- /dev/null
@@ -0,0 +1,72 @@
+/* Verify that -Wstringop-overflow doesn't cause false positives for
+   anti-ranges.  Note that not all of the statements below result in
+   the memset argument being represented as an anti-range.
+
+   { dg-do compile }
+   { dg-options "-O2 -Wstringop-overflow" } */
+
+#define SCHAR_MAX __SCHAR_MAX__
+#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
+
+#define SHRT_MAX  __SHRT_MAX__
+#define USHRT_MAX (SHRT_MAX * 2 + 1)
+
+#define INT_MAX   __INT_MAX__
+#define UINT_MAX  (INT_MAX * 2U + 1)
+
+#define LONG_MAX __LONG_MAX__
+#define ULONG_MAX (LONG_MAX * 2LU + 1)
+
+#define PTRDIFF_MAX __PTRDIFF_MAX__
+#define SIZE_MAX    __SIZE_MAX__
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__    size_t;
+
+#define TEST_AR_1(T, prefix)                   \
+  void test_ar_1_ ## prefix (void *d, T n)     \
+  {                                            \
+    if (n == prefix ## _MAX - 1)               \
+      n = prefix ## _MAX - 2;                  \
+    __builtin_memset (d, 0, n);                        \
+  } typedef void dummy
+
+#define TEST_AR_2(T, prefix)                                   \
+  void test_ar_2_ ## prefix (void *d, T n)                     \
+  {                                                            \
+    if (prefix ## _MAX - 2 <= n && n <= prefix ## _MAX - 1)    \
+      n = prefix ## _MAX - 3;                                  \
+    __builtin_memset (d, 0, n);                                        \
+  } typedef void dummy
+
+/* Verify antirange where MIN == MAX.  */
+TEST_AR_1 (signed char, SCHAR);
+TEST_AR_1 (unsigned char, UCHAR);
+
+TEST_AR_1 (short, SHRT);
+TEST_AR_1 (unsigned short, USHRT);
+
+TEST_AR_1 (int, INT);
+TEST_AR_1 (unsigned, UINT);
+
+TEST_AR_1 (long, LONG);
+TEST_AR_1 (unsigned long, ULONG);
+
+TEST_AR_1 (ptrdiff_t, PTRDIFF);
+TEST_AR_1 (size_t, SIZE);
+
+/* Verify antirange where MIN < MAX.  */
+TEST_AR_2 (signed char, SCHAR);
+TEST_AR_2 (unsigned char, UCHAR);
+
+TEST_AR_2 (short, SHRT);
+TEST_AR_2 (unsigned short, USHRT);
+
+TEST_AR_2 (int, INT);
+TEST_AR_2 (unsigned, UINT);
+
+TEST_AR_2 (long, LONG);
+TEST_AR_2 (unsigned long, ULONG);
+
+TEST_AR_2 (ptrdiff_t, PTRDIFF);
+TEST_AR_2 (size_t, SIZE);
diff --git a/gcc/testsuite/gcc.dg/pr78775.c b/gcc/testsuite/gcc.dg/pr78775.c
new file mode 100644 (file)
index 0000000..120c252
--- /dev/null
@@ -0,0 +1,19 @@
+/* PR c/78775 - [7 Regression] ICE in maybe_warn_alloc_args_overflow
+   { dg-do compile }
+   { dg-options "-O2" } */
+
+int a, b, *c;
+
+int main (void)
+{
+  unsigned long d = 0;
+  while (1)
+    {
+      switch (b)
+      case 'S':
+       d = a;
+      c = __builtin_malloc (d);
+    }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr78973-2.c b/gcc/testsuite/gcc.dg/pr78973-2.c
new file mode 100644 (file)
index 0000000..cc3cfc5
--- /dev/null
@@ -0,0 +1,25 @@
+/* PR c/78973 - warning: ‘memcpy’: specified size exceeds maximum object
+   size [-Wstringop-overflow=]
+
+   This is a companion test for the bug above that verifies that the correct
+   range of the int variable is detected.
+
+   { dg-do compile }
+   { dg-require-effective-target int32plus }
+   { dg-options "-O2 -Walloc-size-larger-than=4" }  */
+
+void *p;
+
+void f (int n)
+{
+  if (n <= 4)
+    p = __builtin_malloc (n);
+  /* { dg-warning "argument 1 range \\\[\[0-9\]+, \[0-9\]+\\\] exceeds maximum object size 4" "ilp32" { xfail { ! lp64 } } .-1 } */
+}
+
+void g (unsigned n)
+{
+  if (n < 5)
+    n = 5;
+  f (n);
+}
diff --git a/gcc/testsuite/gcc.dg/pr78973.c b/gcc/testsuite/gcc.dg/pr78973.c
new file mode 100644 (file)
index 0000000..a6195f0
--- /dev/null
@@ -0,0 +1,20 @@
+/* PR c/78973 - warning: ‘memcpy’: specified size exceeds maximum object size
+
+   Test case for what was initially thought to be a false positive but after
+   deeper investigation turned out to be a true positive.
+
+   { dg-do compile }
+   { dg-options "-O2 -Wall" }  */
+
+void f (void *p, int n)
+{
+  if (n <= 4)
+    __builtin_memset (p, 0, n);   /* { dg-warning "exceeds maximum object size" } */
+}
+
+void g (void *d, unsigned n)
+{
+  if (n < 5)
+    n = 5;
+  f (d, n);
+}