]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
analyzer: fix ICE on negative values for size_t [PR114472]
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 10 Apr 2024 20:43:30 +0000 (16:43 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 10 Apr 2024 20:43:30 +0000 (16:43 -0400)
I made several attempts to fix this properly, but for now apply
a band-aid to at least prevent crashing on such cases.

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 <dmalcolm@redhat.com>
gcc/analyzer/access-diagram.cc
gcc/analyzer/region.cc
gcc/analyzer/store.cc
gcc/testsuite/c-c++-common/analyzer/out-of-bounds-pr114472.c [new file with mode: 0644]

index 85e1049bb8982d1f10f96adcd565398064c78929..500480b6832835e161f2f80902e37a7199ce9a34 100644 (file)
@@ -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,
index 705816b62454d1d40f28cf74f18cf17077f1edf7..7d79b45563fd421894fffde8c541c7f86152a571 100644 (file)
@@ -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 *
index e85a19647f7eaf7375dfd861b87639a45bf8cffd..a36de13c17434a5e5e195b6b900c6a4f47938d5d 100644 (file)
@@ -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 (file)
index 0000000..ef9e771
--- /dev/null
@@ -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" } */
+}