return __builtin_dynamic_object_size (bin, 0);
}
+/* Address expressions. */
+
+struct dynarray_struct
+{
+ long a;
+ char c[16];
+ int b;
+};
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct (size_t sz, size_t off)
+{
+ struct dynarray_struct bin[sz];
+
+ return __builtin_dynamic_object_size (&bin[off].c, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj (size_t sz, size_t off)
+{
+ struct dynarray_struct bin[sz];
+
+ return __builtin_dynamic_object_size (&bin[off].c[4], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj2 (size_t sz, size_t off, size_t *objsz)
+{
+ struct dynarray_struct2
+ {
+ long a;
+ int b;
+ char c[sz];
+ };
+
+ struct dynarray_struct2 bin;
+
+ *objsz = sizeof (bin);
+
+ return __builtin_dynamic_object_size (&bin.c[off], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring (size_t sz, size_t off)
+{
+ char str[sz];
+
+ return __builtin_dynamic_object_size (&str[off], 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring_ptrplus (size_t sz, size_t off)
+{
+ int str[sz];
+
+ return __builtin_dynamic_object_size (str + off, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring_ptrplus2 (size_t sz, size_t off, size_t off2)
+{
+ int str[sz];
+ int *ptr = &str[off];
+
+ return __builtin_dynamic_object_size (ptr + off2, 0);
+}
+
size_t
__attribute__ ((access (__read_write__, 1, 2)))
__attribute__ ((noinline))
}
size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_parmsz (void *obj, size_t sz, size_t off)
+{
+ return __builtin_dynamic_object_size (obj + off, 0);
+}
+
+size_t
__attribute__ ((access (__read_write__, 1, 2)))
__attribute__ ((noinline))
test_parmsz_scaled (int *obj, size_t sz)
}
size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_parmsz_scaled_off (int *obj, size_t sz, size_t off)
+{
+ return __builtin_dynamic_object_size (obj + off, 0);
+}
+
+size_t
__attribute__ ((access (__read_write__, 1, 3)))
__attribute__ ((noinline))
test_parmsz_unknown (void *obj, void *unknown, size_t sz, int cond)
return __builtin_dynamic_object_size (cond ? obj : unknown, 0);
}
+size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_loop (int *obj, size_t sz, size_t start, size_t end, int incr)
+{
+ int *ptr = obj + start;
+
+ for (int i = start; i != end; i = i + incr)
+ {
+ ptr = ptr + incr;
+ if (__builtin_dynamic_object_size (ptr, 0) == 0)
+ return 0;
+ }
+
+ return __builtin_dynamic_object_size (ptr, 0);
+}
+
unsigned nfails = 0;
#define FAIL() ({ \
FAIL ();
if (test_dynarray (__builtin_strlen (argv[0])) != __builtin_strlen (argv[0]))
FAIL ();
+ if (test_dynarray_struct (42, 4) !=
+ ((42 - 4) * sizeof (struct dynarray_struct)
+ - __builtin_offsetof (struct dynarray_struct, c)))
+ FAIL ();
+ if (test_dynarray_struct (42, 48) != 0)
+ FAIL ();
+ if (test_substring (128, 4) != 128 - 4)
+ FAIL ();
+ if (test_substring (128, 142) != 0)
+ FAIL ();
+ if (test_dynarray_struct_subobj (42, 4) != 16 - 4)
+ FAIL ();
+ if (test_dynarray_struct_subobj (42, 48) != 0)
+ FAIL ();
+ size_t objsz = 0;
+ if (test_dynarray_struct_subobj2 (42, 4, &objsz)
+ != objsz - 4 - sizeof (long) - sizeof (int))
+ FAIL ();
+ if (test_substring_ptrplus (128, 4) != (128 - 4) * sizeof (int))
+ FAIL ();
+ if (test_substring_ptrplus (128, 142) != 0)
+ FAIL ();
+ if (test_substring_ptrplus2 (128, 4, 4) != (128 - 8) * sizeof (int))
+ FAIL ();
+ if (test_substring_ptrplus2 (128, 4, -3) != (128 - 1) * sizeof (int))
+ FAIL ();
if (test_dynarray_cond (0) != 16)
FAIL ();
if (test_dynarray_cond (1) != 8)
FAIL ();
if (test_parmsz_unknown (argv[0], argv[0], __builtin_strlen (argv[0]) + 1, 0)
!= -1)
+ if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, -1) != 0)
+ FAIL ();
+ if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, 0)
+ != __builtin_strlen (argv[0]) + 1)
+ FAIL ();
+ if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1,
+ __builtin_strlen (argv[0])) != 1)
+ FAIL ();
+ if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1,
+ __builtin_strlen (argv[0]) + 2) != 0)
+ FAIL ();
+ if (test_parmsz_scaled_off (arr, 42, 2) != 40 * sizeof (int))
+ FAIL ();
+ if (test_loop (arr, 42, 0, 32, 1) != 10 * sizeof (int))
+ FAIL ();
+ if (test_loop (arr, 42, 32, -1, -1) != 0)
+ FAIL ();
+ if (test_loop (arr, 42, 32, 10, -1) != 32 * sizeof (int))
+ FAIL ();
+ if (test_loop (arr, 42, 42, 0, -1) != 42 * sizeof (int))
+ FAIL ();
+ if (test_loop (arr, 42, 44, 0, -1) != 0)
+ FAIL ();
+ if (test_loop (arr, 42, 20, 52, 1) != 0)
FAIL ();
if (nfails > 0)
r = malloc (30);
else
r = calloc (2, 16);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 16))
+ abort ();
+#else
/* We may duplicate this test onto the two exit paths. On one path
the size will be 32, the other it will be 30. If we don't duplicate
this test, then the size will be 32. */
if (__builtin_object_size (r, 0) != 2 * 16
&& __builtin_object_size (r, 0) != 30)
abort ();
+#endif
if (x < 20)
r = malloc (30);
else
r = calloc (2, 14);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 14))
+ abort ();
+#else
if (__builtin_object_size (r, 0) != 30)
abort ();
+#endif
if (x < 30)
r = malloc (sizeof (a));
else
r = &a.a[3];
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+ abort ();
+#else
if (__builtin_object_size (r, 0) != sizeof (a))
abort ();
+#endif
r = memcpy (r, "a", 2);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+ abort ();
+#else
if (__builtin_object_size (r, 0) != sizeof (a))
abort ();
+#endif
r = memcpy (r + 2, "b", 2) + 2;
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 0)
+ != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7))
+ abort ();
+#else
if (__builtin_object_size (r, 0) != sizeof (a) - 4)
abort ();
+#endif
r = &a.a[4];
r = memset (r, 'a', 2);
if (__builtin_object_size (r, 0)
abort ();
if (__builtin_object_size (var + 10, 0) != x)
abort ();
+ if (__builtin_object_size (&var[5], 0) != x + 5)
+ abort ();
#else
if (__builtin_object_size (var, 0) != (size_t) -1)
abort ();
if (__builtin_object_size (var + 10, 0) != (size_t) -1)
abort ();
-#endif
if (__builtin_object_size (&var[5], 0) != (size_t) -1)
abort ();
+#endif
if (__builtin_object_size (zerol, 0) != 0)
abort ();
if (__builtin_object_size (&zerol, 0) != 0)
r = malloc (30);
else
r = calloc (2, 16);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 16))
+ abort ();
+#else
/* We may duplicate this test onto the two exit paths. On one path
the size will be 32, the other it will be 30. If we don't duplicate
this test, then the size will be 32. */
if (__builtin_object_size (r, 1) != 2 * 16
&& __builtin_object_size (r, 1) != 30)
abort ();
+#endif
if (x < 20)
r = malloc (30);
else
r = calloc (2, 14);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 14))
+ abort ();
+#else
if (__builtin_object_size (r, 1) != 30)
abort ();
+#endif
if (x < 30)
r = malloc (sizeof (a));
else
r = &a.a[3];
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+ abort ();
+#else
if (__builtin_object_size (r, 1) != sizeof (a))
abort ();
+#endif
r = memcpy (r, "a", 2);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+ abort ();
+#else
if (__builtin_object_size (r, 1) != sizeof (a))
abort ();
+#endif
r = memcpy (r + 2, "b", 2) + 2;
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 0)
+ != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7))
+ abort ();
+#else
if (__builtin_object_size (r, 1) != sizeof (a) - 4)
abort ();
+#endif
r = &a.a[4];
r = memset (r, 'a', 2);
if (__builtin_object_size (r, 1) != sizeof (a.a) - 4)
abort ();
if (__builtin_object_size (var + 10, 1) != x)
abort ();
+ if (__builtin_object_size (&var[5], 1) != x + 5)
+ abort ();
+ if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A))
+ abort ();
+ if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A))
+ abort ();
+ if (__builtin_object_size (&vara[5], 1) != (x + 5) * sizeof (struct A))
+ abort ();
#else
if (__builtin_object_size (var, 1) != (size_t) -1)
abort ();
if (__builtin_object_size (var + 10, 1) != (size_t) -1)
abort ();
-#endif
if (__builtin_object_size (&var[5], 1) != (size_t) -1)
abort ();
-#ifdef __builtin_object_size
- if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A))
- abort ();
- if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A))
- abort ();
-#else
if (__builtin_object_size (vara, 1) != (size_t) -1)
abort ();
if (__builtin_object_size (vara + 10, 1) != (size_t) -1)
abort ();
-#endif
if (__builtin_object_size (&vara[5], 1) != (size_t) -1)
abort ();
+#endif
if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a))
abort ();
if (__builtin_object_size (&vara[10].a[0], 1) != sizeof (vara[0].a))
abort ();
if (__builtin_object_size (q, 2) != 0)
abort ();
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 2)
+ != (x < 0
+ ? sizeof (a) - __builtin_offsetof (struct A, a) - 9
+ : sizeof (a) - __builtin_offsetof (struct A, c) - 1))
+ abort ();
+#else
if (__builtin_object_size (r, 2)
!= sizeof (a) - __builtin_offsetof (struct A, c) - 1)
abort ();
+#endif
if (x < 6)
r = &w[2].a[1];
else
if (__builtin_object_size (&y.b, 2)
!= sizeof (a) - __builtin_offsetof (struct A, b))
abort ();
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 2)
+ != (x < 6
+ ? 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1
+ : sizeof (a) - __builtin_offsetof (struct A, a) - 6))
+ abort ();
+#else
if (__builtin_object_size (r, 2)
!= sizeof (a) - __builtin_offsetof (struct A, a) - 6)
abort ();
+#endif
if (x < 20)
r = malloc (30);
else
r = calloc (2, 16);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (r, 2) != (x < 20 ? 30 : 2 * 16))
+ abort ();
+#else
if (__builtin_object_size (r, 2) != 30)
abort ();
+#endif
if (x < 20)
r = malloc (30);
else
abort ();
if (__builtin_object_size (var + 10, 2) != x)
abort ();
+ if (__builtin_object_size (&var[5], 2) != x + 5)
+ abort ();
#else
if (__builtin_object_size (var, 2) != 0)
abort ();
if (__builtin_object_size (var + 10, 2) != 0)
abort ();
-#endif
if (__builtin_object_size (&var[5], 2) != 0)
abort ();
+#endif
if (__builtin_object_size (zerol, 2) != 0)
abort ();
if (__builtin_object_size (&zerol, 2) != 0)
abort ();
if (__builtin_object_size (var + 10, 3) != x)
abort ();
+ if (__builtin_object_size (&var[5], 3) != x + 5)
+ abort ();
+ if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A))
+ abort ();
+ if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A))
+ abort ();
+ if (__builtin_object_size (&vara[5], 3) != (x + 5) * sizeof (struct A))
+ abort ();
#else
if (__builtin_object_size (var, 3) != 0)
abort ();
if (__builtin_object_size (var + 10, 3) != 0)
abort ();
-#endif
if (__builtin_object_size (&var[5], 3) != 0)
abort ();
-#ifdef __builtin_object_size
- if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A))
- abort ();
- if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A))
- abort ();
-#else
if (__builtin_object_size (vara, 3) != 0)
abort ();
if (__builtin_object_size (vara + 10, 3) != 0)
abort ();
-#endif
if (__builtin_object_size (&vara[5], 3) != 0)
abort ();
+#endif
if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a))
abort ();
if (__builtin_object_size (&vara[10].a[0], 3) != sizeof (vara[0].a))
? integer_zerop (val) : integer_all_onesp (val));
}
+/* Return true if VAL represents a valid size for OBJECT_SIZE_TYPE. */
+
+static inline bool
+size_valid_p (tree val, int object_size_type)
+{
+ return ((object_size_type & OST_DYNAMIC) || TREE_CODE (val) == INTEGER_CST);
+}
+
/* Return true if VAL is usable as an object size in the object_sizes
vectors. */
static tree
size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE)
{
- gcc_checking_assert (TREE_CODE (offset) == INTEGER_CST);
gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype));
/* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net
sz = wholesize = size_unknown (object_size_type);
}
if (!size_unknown_p (sz, object_size_type))
- {
- tree offset = TREE_OPERAND (pt_var, 1);
- if (TREE_CODE (offset) != INTEGER_CST
- || TREE_CODE (sz) != INTEGER_CST)
- sz = wholesize = size_unknown (object_size_type);
- else
- sz = size_for_offset (sz, offset, wholesize);
- }
+ sz = size_for_offset (sz, TREE_OPERAND (pt_var, 1), wholesize);
if (!size_unknown_p (sz, object_size_type)
- && TREE_CODE (sz) == INTEGER_CST
- && compare_tree_int (sz, offset_limit) < 0)
+ && (TREE_CODE (sz) != INTEGER_CST
+ || compare_tree_int (sz, offset_limit) < 0))
{
pt_var_size = sz;
pt_var_wholesize = wholesize;
if (pt_var_size)
{
- /* Validate the size determined above. */
- if (compare_tree_int (pt_var_size, offset_limit) >= 0)
+ /* Validate the size determined above if it is a constant. */
+ if (TREE_CODE (pt_var_size) == INTEGER_CST
+ && compare_tree_int (pt_var_size, offset_limit) >= 0)
return false;
}
var = TREE_OPERAND (var, 0);
if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
|| ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
- || (pt_var_size
+ || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST
&& tree_int_cst_lt (pt_var_size,
TYPE_SIZE_UNIT (TREE_TYPE (var)))))
var = pt_var;
switch (TREE_CODE (v))
{
case ARRAY_REF:
- if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))
- && TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST)
+ if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0))))
{
tree domain
= TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
- if (domain
- && TYPE_MAX_VALUE (domain)
- && TREE_CODE (TYPE_MAX_VALUE (domain))
- == INTEGER_CST
- && tree_int_cst_lt (TREE_OPERAND (v, 1),
- TYPE_MAX_VALUE (domain)))
+ if (domain && TYPE_MAX_VALUE (domain))
{
v = NULL_TREE;
break;
var = pt_var;
if (var != pt_var)
- var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+ {
+ var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+ if (!TREE_CONSTANT (var_size))
+ var_size = get_or_create_ssa_default_def (cfun, var_size);
+ if (!var_size)
+ return false;
+ }
else if (!pt_var_size)
return false;
else
var_size = pt_var_size;
bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
if (bytes != error_mark_node)
- {
- if (TREE_CODE (bytes) == INTEGER_CST
- && tree_int_cst_lt (var_size, bytes))
- bytes = size_zero_node;
- else
- bytes = size_binop (MINUS_EXPR, var_size, bytes);
- }
+ bytes = size_for_offset (var_size, bytes);
if (var != pt_var
&& pt_var_size
&& TREE_CODE (pt_var) == MEM_REF
tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
if (bytes2 != error_mark_node)
{
- if (TREE_CODE (bytes2) == INTEGER_CST
- && tree_int_cst_lt (pt_var_size, bytes2))
- bytes2 = size_zero_node;
- else
- bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2);
+ bytes2 = size_for_offset (pt_var_size, bytes2);
bytes = size_binop (MIN_EXPR, bytes, bytes2);
}
}
wholebytes = pt_var_wholesize;
}
- if (TREE_CODE (bytes) != INTEGER_CST
- || TREE_CODE (wholebytes) != INTEGER_CST)
- return false;
+ if (!size_unknown_p (bytes, object_size_type)
+ && size_valid_p (bytes, object_size_type)
+ && !size_unknown_p (bytes, object_size_type)
+ && size_valid_p (wholebytes, object_size_type))
+ {
+ *psize = bytes;
+ if (pwholesize)
+ *pwholesize = wholebytes;
+ return true;
+ }
- *psize = bytes;
- if (pwholesize)
- *pwholesize = wholebytes;
- return true;
+ return false;
}
tree offset = gimple_assign_rhs2 (def);
ptr = gimple_assign_rhs1 (def);
- if (tree_fits_shwi_p (offset)
+ if (((object_size_type & OST_DYNAMIC)
+ || tree_fits_shwi_p (offset))
&& compute_builtin_object_size (ptr, object_size_type,
psize))
{
- /* Return zero when the offset is out of bounds. */
*psize = size_for_offset (*psize, offset);
return true;
}
gcc_assert (osi->pass == 0);
tree bytes = alloc_object_size (call, object_size_type);
- if (!(object_size_type & OST_DYNAMIC) && TREE_CODE (bytes) != INTEGER_CST)
+ if (!size_valid_p (bytes, object_size_type))
bytes = size_unknown (object_size_type);
object_sizes_set (osi, varno, bytes, bytes);
return false;
/* Handle PTR + OFFSET here. */
- if (TREE_CODE (op1) == INTEGER_CST
- && (TREE_CODE (op0) == SSA_NAME
- || TREE_CODE (op0) == ADDR_EXPR))
+ if (size_valid_p (op1, object_size_type)
+ && (TREE_CODE (op0) == SSA_NAME || TREE_CODE (op0) == ADDR_EXPR))
{
if (TREE_CODE (op0) == SSA_NAME)
{
else
bytes = wholesize = size_unknown (object_size_type);
+ if (!size_valid_p (bytes, object_size_type)
+ || !size_valid_p (wholesize, object_size_type))
+ bytes = wholesize = size_unknown (object_size_type);
+
if (object_sizes_set (osi, varno, bytes, wholesize))
osi->changed = true;
return reexamine;