@@ -22,6 +22,8 @@ struct A
extern char exta[];
extern char extb[30];
extern struct A zerol[0];
+int off = 2;
+int off2 = -3;
void
__attribute__ ((noinline))
@@ -162,6 +164,13 @@ test1 (void *q, int x)
if (__builtin_object_size (&extb[5], 0) != sizeof (extb) - 5)
abort ();
#ifdef __builtin_object_size
+ if (__builtin_object_size (&extb[off], 0) != sizeof (extb) - off)
+ abort ();
+ r = &extb[5];
+ if (__builtin_object_size (r + off, 0) != sizeof (extb) - 5 - off)
+ abort ();
+ if (__builtin_object_size (r + off2, 0) != sizeof (extb) - 5 - off2)
+ abort ();
if (__builtin_object_size (var, 0) != x + 10)
abort ();
if (__builtin_object_size (var + 10, 0) != x)
@@ -169,6 +178,13 @@ test1 (void *q, int x)
if (__builtin_object_size (&var[5], 0) != x + 5)
abort ();
#else
+ if (__builtin_object_size (&extb[off], 0) != sizeof (extb))
+ abort ();
+ r = &extb[5];
+ if (__builtin_object_size (r + off, 0) != sizeof (extb))
+ abort ();
+ if (__builtin_object_size (r + off2, 0) != sizeof (extb))
+ abort ();
if (__builtin_object_size (var, 0) != (size_t) -1)
abort ();
if (__builtin_object_size (var + 10, 0) != (size_t) -1)
@@ -24,6 +24,9 @@ extern char extb[30];
extern struct A extc[];
struct A zerol[0];
+int off = 3;
+int off2 = -3;
+
void
__attribute__ ((noinline))
test1 (void *q, int x)
@@ -151,6 +154,23 @@ test1 (void *q, int x)
abort ();
if (__builtin_object_size (&extb[5], 1) != sizeof (extb) - 5)
abort ();
+#ifdef __builtin_object_size
+ if (__builtin_object_size (&extb[off], 1) != sizeof (extb) - off)
+ abort ();
+ r = &extb[5];
+ if (__builtin_object_size (r + off, 1) != sizeof (extb) - 5 - off)
+ abort ();
+ if (__builtin_object_size (r + off2, 0) != sizeof (extb) - 5 - off2)
+ abort ();
+#else
+ if (__builtin_object_size (&extb[off], 1) != sizeof (extb))
+ abort ();
+ r = &extb[5];
+ if (__builtin_object_size (r + off, 1) != sizeof (extb))
+ abort ();
+ if (__builtin_object_size (r + off2, 0) != sizeof (extb))
+ abort ();
+#endif
if (__builtin_object_size (extc, 1) != (size_t) -1)
abort ();
if (__builtin_object_size (extc + 10, 1) != (size_t) -1)
@@ -200,6 +220,23 @@ test1 (void *q, int x)
abort ();
if (__builtin_object_size (&vara[7].c[7], 1) != sizeof (vara[0].c) - 7)
abort ();
+#ifdef __builtin_object_size
+ if (__builtin_object_size (&vara[5].c[off], 1) != sizeof (vara[0].c) - off)
+ abort ();
+ r = &vara[1].c[5];
+ if (__builtin_object_size (r + off, 1) != sizeof (vara[0].c) - 5 - off)
+ abort ();
+ if (__builtin_object_size (r + off2, 1) != sizeof (vara[0].c) - 5 - off2)
+ abort ();
+#else
+ if (__builtin_object_size (&vara[5].c[off], 1) != sizeof (vara[0].c))
+ abort ();
+ r = &vara[1].c[5];
+ if (__builtin_object_size (r + off, 1) != sizeof (vara[0].c))
+ abort ();
+ if (__builtin_object_size (r + off2, 1) != sizeof (vara[0].c))
+ abort ();
+#endif
if (__builtin_object_size (zerol, 1) != 0)
abort ();
if (__builtin_object_size (&zerol, 1) != 0)
@@ -347,10 +347,21 @@ init_offset_limit (void)
be positive and hence, be within OFFSET_LIMIT for valid offsets. */
static tree
-size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE)
+size_for_offset (int object_size_type,tree sz, tree offset,
+ tree wholesize = NULL_TREE)
{
gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype));
+ /* When maximum size is requested and the offset is non-constant, return the
+ whole size instead of bailing out in __builtin_object_size. */
+ if (!(object_size_type & (OST_MINIMUM | OST_DYNAMIC))
+ && TREE_CODE (offset) != INTEGER_CST)
+ {
+ if (wholesize)
+ sz = wholesize;
+ offset = size_zero_node;
+ }
+
/* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net
offset from the whole object. */
if (wholesize && wholesize != sz
@@ -547,7 +558,8 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
sz = wholesize = size_unknown (object_size_type);
}
if (!size_unknown_p (sz, object_size_type))
- sz = size_for_offset (sz, TREE_OPERAND (pt_var, 1), wholesize);
+ sz = size_for_offset (object_size_type, sz, TREE_OPERAND (pt_var, 1),
+ wholesize);
if (!size_unknown_p (sz, object_size_type)
&& (TREE_CODE (sz) != INTEGER_CST
@@ -695,7 +707,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
var_size = pt_var_size;
bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
if (bytes != error_mark_node)
- bytes = size_for_offset (var_size, bytes);
+ bytes = size_for_offset (object_size_type, var_size, bytes);
if (var != pt_var
&& pt_var_size
&& TREE_CODE (pt_var) == MEM_REF
@@ -704,7 +716,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
if (bytes2 != error_mark_node)
{
- bytes2 = size_for_offset (pt_var_size, bytes2);
+ bytes2 = size_for_offset (object_size_type, pt_var_size, bytes2);
bytes = size_binop (MIN_EXPR, bytes, bytes2);
}
}
@@ -1058,7 +1070,7 @@ compute_builtin_object_size (tree ptr, int object_size_type,
&& compute_builtin_object_size (ptr, object_size_type,
psize))
{
- *psize = size_for_offset (*psize, offset);
+ *psize = size_for_offset (object_size_type, *psize, offset);
return true;
}
}
@@ -1323,43 +1335,42 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt)
return false;
/* Handle PTR + OFFSET here. */
- if (((object_size_type & OST_DYNAMIC) || TREE_CODE (op1) == INTEGER_CST)
- && (TREE_CODE (op0) == SSA_NAME
- || TREE_CODE (op0) == ADDR_EXPR))
+ if (TREE_CODE (op0) == SSA_NAME)
{
- if (TREE_CODE (op0) == SSA_NAME)
- {
- if (osi->pass == 0)
- collect_object_sizes_for (osi, op0);
+ if (osi->pass == 0)
+ collect_object_sizes_for (osi, op0);
- bytes = object_sizes_get (osi, SSA_NAME_VERSION (op0));
- wholesize = object_sizes_get (osi, SSA_NAME_VERSION (op0), true);
- reexamine = bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (op0));
- }
- else
- {
- /* op0 will be ADDR_EXPR here. We should never come here during
- reexamination. */
- gcc_checking_assert (osi->pass == 0);
- addr_object_size (osi, op0, object_size_type, &bytes, &wholesize);
- }
-
- /* In the first pass, do not compute size for offset if either the
- maximum size is unknown or the minimum size is not initialized yet;
- the latter indicates a dependency loop and will be resolved in
- subsequent passes. We attempt to compute offset for 0 minimum size
- too because a negative offset could be within bounds of WHOLESIZE,
- giving a non-zero result for VAR. */
- if (osi->pass != 0 || !size_unknown_p (bytes, 0))
- bytes = size_for_offset (bytes, op1, wholesize);
+ bytes = object_sizes_get (osi, SSA_NAME_VERSION (op0));
+ wholesize = object_sizes_get (osi, SSA_NAME_VERSION (op0), true);
+ reexamine = bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (op0));
+ }
+ else if (TREE_CODE (op0) == ADDR_EXPR)
+ {
+ /* op0 will be ADDR_EXPR here. We should never come here during
+ reexamination. */
+ gcc_checking_assert (osi->pass == 0);
+ addr_object_size (osi, op0, object_size_type, &bytes, &wholesize);
}
else
- bytes = wholesize = size_unknown (object_size_type);
+ {
+ bytes = wholesize = size_unknown (object_size_type);
+ goto out;
+ }
+
+ /* In the first pass, do not compute size for offset if either the
+ maximum size is unknown or the minimum size is not initialized yet;
+ the latter indicates a dependency loop and will be resolved in
+ subsequent passes. We attempt to compute offset for 0 minimum size
+ too because a negative offset could be within bounds of WHOLESIZE,
+ giving a non-zero result for VAR. */
+ if (osi->pass != 0 || !size_unknown_p (bytes, 0))
+ bytes = size_for_offset (object_size_type, bytes, op1, wholesize);
if (!size_valid_p (bytes, object_size_type)
|| !size_valid_p (wholesize, object_size_type))
bytes = wholesize = size_unknown (object_size_type);
+out:
if (object_sizes_set (osi, varno, bytes, wholesize))
osi->changed = true;
return reexamine;
This partially fixes middle-end/77608 by making __builtin_object_size return the whole object size instead of bailing out in case the offset in the object is variable and the maximum estimate is requested. gcc/ChangeLog: PR middle-end/77608 * tree-object-size.c (size_for_offset): New object_size_type parameter. Return known whole size if offset is not constant. (addr_object_size, compute_builtin_object_size): Adjust. (plus_stmt_object_size): Defer constness check of offset to size_for_offset. gcc/testsuite/ChangeLog: PR middle-end/77608 * gcc.dg/builtin-object-size-1.c (test1): Add tests. * gcc.dg/builtin-object-size-2.c (test1): Likewise. Signed-off-by: Siddhesh Poyarekar <siddhesh@gotplt.org> --- This applies on top of the __builtin_dynamic_object_size patchset. It should be possible to process trees with side effects and fully fix 77608, but I'll do that later since it would be a bit more involved. Tested with a full bootstrap on x86_64 and ubsan bootstrap. gcc/testsuite/gcc.dg/builtin-object-size-1.c | 16 ++++ gcc/testsuite/gcc.dg/builtin-object-size-2.c | 37 ++++++++++ gcc/tree-object-size.c | 77 +++++++++++--------- 3 files changed, 97 insertions(+), 33 deletions(-)