diff --git a/gcc/testsuite/g++.dg/ext/builtin-object-size2.C b/gcc/testsuite/g++.dg/ext/builtin-object-size2.C index 7a8f4e6273320b433399dd9013f73b231be64cf1..45401b5a9c13fb08ab6ba898be8471e6dd6c3a91 100644 --- a/gcc/testsuite/g++.dg/ext/builtin-object-size2.C +++ b/gcc/testsuite/g++.dg/ext/builtin-object-size2.C @@ -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 (); } diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index ec2c62c96401316799167afea8bbfaf014eb7def..e0c967e003f60ca1eba43213e99e2a615dd3a46b 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -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; diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc index 09aad88498eabe6d64fe682a8850d6d1b337c894..6413ebcca37c72f2a20cd2a8620438fd637647c7 100644 --- a/gcc/tree-object-size.cc +++ b/gcc/tree-object-size.cc @@ -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. */