mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-27 05:44:15 +08:00
tree-optimization/117355: object size for PHI nodes with negative offsets
When the object size estimate is returned for a PHI node, it is the maximum possible value, which is fine in isolation. When combined with negative offsets however, it may sometimes end up in zero size because the resultant size was larger than the wholesize, leading size_for_offset to conclude that there's a potential underflow. Fix this by allowing a non-strict mode to size_for_offset, which conservatively returns the size (or wholesize) in case of a negative offset. gcc/ChangeLog: PR tree-optimization/117355 * tree-object-size.cc (size_for_offset): New argument STRICT, return SZ if it is set to false. (plus_stmt_object_size): Adjust call to SIZE_FOR_OFFSET. gcc/testsuite/ChangeLog: PR tree-optimization/117355 * g++.dg/ext/builtin-object-size2.C (test9): New test. (main): Call it. * gcc.dg/builtin-object-size-3.c (test10): Adjust expected size. Signed-off-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
This commit is contained in:
parent
5f95136e5e
commit
684595188d
@ -406,6 +406,32 @@ test8 (union F *f)
|
||||
FAIL ();
|
||||
}
|
||||
|
||||
// PR117355
|
||||
#define STR "bbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test9 (void)
|
||||
{
|
||||
char line[256];
|
||||
const char *p = STR;
|
||||
const char *q = p + sizeof (STR) - 1;
|
||||
|
||||
char *q1 = line;
|
||||
for (const char *p1 = p; p1 < q;)
|
||||
{
|
||||
*q1++ = *p1++;
|
||||
|
||||
if (p1 < q && (*q1++ = *p1++) != '\0')
|
||||
{
|
||||
if (__builtin_object_size (q1 - 2, 0) == 0)
|
||||
__builtin_abort ();
|
||||
if (__builtin_object_size (q1 - 2, 1) == 0)
|
||||
__builtin_abort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
@ -430,5 +456,6 @@ main (void)
|
||||
union F f, *fp = &f;
|
||||
__asm ("" : "+r" (fp));
|
||||
test8 (fp);
|
||||
test9 ();
|
||||
DONE ();
|
||||
}
|
||||
|
@ -619,7 +619,7 @@ test10 (void)
|
||||
if (__builtin_object_size (p - 3, 2) != sizeof (buf) - i + 3)
|
||||
FAIL ();
|
||||
#else
|
||||
if (__builtin_object_size (p - 3, 2) != 0)
|
||||
if (__builtin_object_size (p - 3, 2) != 3)
|
||||
FAIL ();
|
||||
#endif
|
||||
break;
|
||||
|
@ -344,7 +344,8 @@ 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 (tree sz, tree offset, tree wholesize = NULL_TREE,
|
||||
bool strict = true)
|
||||
{
|
||||
gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype));
|
||||
|
||||
@ -377,9 +378,17 @@ size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE)
|
||||
return sz;
|
||||
|
||||
/* Negative or too large offset even after adjustment, cannot be within
|
||||
bounds of an object. */
|
||||
bounds of an object. The exception here is when the base object size
|
||||
has been overestimated (e.g. through PHI nodes or a COND_EXPR) and the
|
||||
adjusted offset remains negative. If the caller wants to be
|
||||
permissive, return the base size. */
|
||||
if (compare_tree_int (offset, offset_limit) > 0)
|
||||
return size_zero_node;
|
||||
{
|
||||
if (strict)
|
||||
return size_zero_node;
|
||||
else
|
||||
return sz;
|
||||
}
|
||||
}
|
||||
|
||||
return size_binop (MINUS_EXPR, size_binop (MAX_EXPR, sz, offset), offset);
|
||||
@ -1521,16 +1530,23 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt)
|
||||
addr_object_size (osi, op0, object_size_type, &bytes, &wholesize);
|
||||
}
|
||||
|
||||
bool pos_offset = (size_valid_p (op1, 0)
|
||||
&& compare_tree_int (op1, offset_limit) <= 0);
|
||||
|
||||
/* size_for_offset doesn't make sense for -1 size, but it does for size 0
|
||||
since the wholesize could be non-zero and a negative offset could give
|
||||
a non-zero size. */
|
||||
if (size_unknown_p (bytes, 0))
|
||||
;
|
||||
/* In the static case, We want SIZE_FOR_OFFSET to go a bit easy on us if
|
||||
it sees a negative offset since BYTES could have been
|
||||
overestimated. */
|
||||
else if ((object_size_type & OST_DYNAMIC)
|
||||
|| bytes != wholesize
|
||||
|| (size_valid_p (op1, object_size_type)
|
||||
&& compare_tree_int (op1, offset_limit) <= 0))
|
||||
bytes = size_for_offset (bytes, op1, wholesize);
|
||||
|| pos_offset)
|
||||
bytes = size_for_offset (bytes, op1, wholesize,
|
||||
((object_size_type & OST_DYNAMIC)
|
||||
|| pos_offset));
|
||||
/* In the static case, with a negative offset, the best estimate for
|
||||
minimum size is size_unknown but for maximum size, the wholesize is a
|
||||
better estimate than size_unknown. */
|
||||
|
Loading…
Reference in New Issue
Block a user