I made several attempts to fix this properly, but for now apply a band-aid to at least prevent crashing on such cases.
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Successful run of analyzer integration tests on x86_64-pc-linux-gnu. Pushed to trunk as r14-9902-g4a94551d7eaaf7. gcc/analyzer/ChangeLog: PR analyzer/114472 * access-diagram.cc (bit_size_expr::maybe_get_formatted_str): Reject attempts to print sizes that are too large. * region.cc (region_offset::calc_symbolic_bit_offset): Use a typeless svalue for the bit offset. * store.cc (bit_range::intersects_p): Replace assertion with test. (bit_range::exceeds_p): Likewise. (bit_range::falls_short_of_p): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/analyzer/out-of-bounds-pr114472.c: New test. Signed-off-by: David Malcolm <dmalc...@redhat.com> --- gcc/analyzer/access-diagram.cc | 4 ++++ gcc/analyzer/region.cc | 2 +- gcc/analyzer/store.cc | 20 +++++++++++++++---- .../analyzer/out-of-bounds-pr114472.c | 17 ++++++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/analyzer/out-of-bounds-pr114472.c diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc index 4cb6570e90b9..873205c46499 100644 --- a/gcc/analyzer/access-diagram.cc +++ b/gcc/analyzer/access-diagram.cc @@ -373,6 +373,8 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm, if (tree cst = num_bytes->maybe_get_constant ()) { byte_size_t concrete_num_bytes = wi::to_offset (cst); + if (!wi::fits_uhwi_p (concrete_num_bytes)) + return nullptr; if (concrete_num_bytes == 1) return ::make_unique <text_art::styled_string> (fmt_styled_string (sm, concrete_single_byte_fmt, @@ -396,6 +398,8 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm, else if (tree cst = m_num_bits.maybe_get_constant ()) { bit_size_t concrete_num_bits = wi::to_offset (cst); + if (!wi::fits_uhwi_p (concrete_num_bits)) + return nullptr; if (concrete_num_bits == 1) return ::make_unique <text_art::styled_string> (fmt_styled_string (sm, concrete_single_bit_fmt, diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index 705816b62454..7d79b45563fd 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -89,7 +89,7 @@ region_offset::calc_symbolic_bit_offset (region_model_manager *mgr) const m_sym_offset, bits_per_byte); } else - return *mgr->get_or_create_int_cst (size_type_node, m_offset); + return *mgr->get_or_create_int_cst (NULL_TREE, m_offset); } const svalue * diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index e85a19647f7e..a36de13c1743 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -290,7 +290,10 @@ bit_range::intersects_p (const bit_range &other, bit_offset_t overlap_next = MIN (get_next_bit_offset (), other.get_next_bit_offset ()); - gcc_assert (overlap_next > overlap_start); + if (overlap_next <= overlap_start) + /* If this has happened, some kind of overflow has happened in + our arithmetic. For now, reject such cases. */ + return false; bit_range abs_overlap_bits (overlap_start, overlap_next - overlap_start); *out_this = abs_overlap_bits - get_start_bit_offset (); *out_other = abs_overlap_bits - other.get_start_bit_offset (); @@ -316,7 +319,10 @@ bit_range::intersects_p (const bit_range &other, other.get_start_bit_offset ()); bit_offset_t overlap_next = MIN (get_next_bit_offset (), other.get_next_bit_offset ()); - gcc_assert (overlap_next > overlap_start); + if (overlap_next <= overlap_start) + /* If this has happened, some kind of overflow has happened in + our arithmetic. For now, reject such cases. */ + return false; *out_num_overlap_bits = overlap_next - overlap_start; return true; } @@ -339,7 +345,10 @@ bit_range::exceeds_p (const bit_range &other, bit_offset_t start = MAX (get_start_bit_offset (), other.get_next_bit_offset ()); bit_offset_t size = get_next_bit_offset () - start; - gcc_assert (size > 0); + if (size <= 0) + /* If this has happened, some kind of overflow has happened in + our arithmetic. For now, reject such cases. */ + return false; out_overhanging_bit_range->m_start_bit_offset = start; out_overhanging_bit_range->m_size_in_bits = size; return true; @@ -362,7 +371,10 @@ bit_range::falls_short_of_p (bit_offset_t offset, /* THIS falls short of OFFSET. */ bit_offset_t start = get_start_bit_offset (); bit_offset_t size = MIN (offset, get_next_bit_offset ()) - start; - gcc_assert (size > 0); + if (size <= 0) + /* If this has happened, some kind of overflow has happened in + our arithmetic. For now, reject such cases. */ + return false; out_fall_short_bits->m_start_bit_offset = start; out_fall_short_bits->m_size_in_bits = size; return true; diff --git a/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-pr114472.c b/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-pr114472.c new file mode 100644 index 000000000000..ef9e7711a2e4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-pr114472.c @@ -0,0 +1,17 @@ +/* Verify we don't ICE on cases involving very large values for size. */ + +char s, d; + +void +foo(void) +{ + __builtin_strncpy(&d, &s + 3, -1); /* { dg-warning "Wstringop-overflow" } */ + __builtin_strncpy(&d + 3, &s, -1); /* { dg-warning "Wstringop-overflow" } */ +} + +void +bar(void) +{ + __builtin_strncpy(&d, &s - 3, -1); /* { dg-warning "Wstringop-overflow" } */ + __builtin_strncpy(&d - 3, &s, -1); /* { dg-warning "Wstringop-overflow" } */ +} -- 2.26.3