public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-2582] analyzer: consider empty ranges and zero byte accesses [PR106845]
@ 2022-09-11 22:02 Tim Lange
  0 siblings, 0 replies; only message in thread
From: Tim Lange @ 2022-09-11 22:02 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:0ea5e3f4542832b8da016b152695e64a2a386309

commit r13-2582-g0ea5e3f4542832b8da016b152695e64a2a386309
Author: Tim Lange <mail@tim-lange.me>
Date:   Sat Sep 10 23:53:48 2022 +0200

    analyzer: consider empty ranges and zero byte accesses [PR106845]
    
    This patch adds handling of empty ranges in bit_range and byte_range and
    adds an assertion to member functions that assume a positive size.
    Further, the patch fixes an ICE caused by an empty byte_range passed to
    byte_range::exceeds_p.
    
    Regression-tested on Linux x86_64.
    
    2022-09-10  Tim Lange  <mail@tim-lange.me>
    
    gcc/analyzer/ChangeLog:
    
            PR analyzer/106845
            * region-model.cc (region_model::check_region_bounds):
            Bail out if 0 bytes were accessed.
            * store.cc (byte_range::dump_to_pp):
            Add special case for empty ranges.
            (byte_range::exceeds_p): Restrict to non-empty ranges.
            (byte_range::falls_short_of_p): Restrict to non-empty ranges.
            * store.h (bit_range::empty_p): New function.
            (bit_range::get_last_byte_offset): Restrict to non-empty ranges.
            (byte_range::empty_p): New function.
            (byte_range::get_last_byte_offset): Restrict to non-empty ranges.
    
    gcc/testsuite/ChangeLog:
    
            PR analyzer/106845
            * gcc.dg/analyzer/out-of-bounds-zero.c: New test.
            * gcc.dg/analyzer/pr106845.c: New test.

Diff:
---
 gcc/analyzer/region-model.cc                       |  3 +
 gcc/analyzer/store.cc                              | 12 +++-
 gcc/analyzer/store.h                               | 12 ++++
 gcc/testsuite/gcc.dg/analyzer/out-of-bounds-zero.c | 67 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/analyzer/pr106845.c           | 11 ++++
 5 files changed, 103 insertions(+), 2 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 6eeb684844d..13b8e3eaf1b 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1828,6 +1828,9 @@ region_model::check_region_bounds (const region *reg,
   /* Find out how many bytes were accessed.  */
   const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
   tree num_bytes_tree = maybe_get_integer_cst_tree (num_bytes_sval);
+  /* Bail out if 0 bytes are accessed.  */
+  if (num_bytes_tree && zerop (num_bytes_tree))
+    return;
 
   /* Get the capacity of the buffer.  */
   const svalue *capacity = get_capacity (base_reg);
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index ec5232cb055..1857d95f0b6 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -380,7 +380,11 @@ bit_range::as_byte_range (byte_range *out) const
 void
 byte_range::dump_to_pp (pretty_printer *pp) const
 {
-  if (m_size_in_bytes == 1)
+  if (m_size_in_bytes == 0)
+    {
+      pp_string (pp, "empty");
+    }
+  else if (m_size_in_bytes == 1)
     {
       pp_string (pp, "byte ");
       pp_wide_int (pp, m_start_byte_offset, SIGNED);
@@ -455,7 +459,9 @@ bool
 byte_range::exceeds_p (const byte_range &other,
 		       byte_range *out_overhanging_byte_range) const
 {
-  if (other.get_last_byte_offset () < get_last_byte_offset ())
+  gcc_assert (!empty_p ());
+
+  if (other.get_next_byte_offset () < get_next_byte_offset ())
     {
       /* THIS definitely exceeds OTHER.  */
       byte_offset_t start = MAX (get_start_byte_offset (),
@@ -477,6 +483,8 @@ bool
 byte_range::falls_short_of_p (byte_offset_t offset,
 			      byte_range *out_fall_short_bytes) const
 {
+  gcc_assert (!empty_p ());
+
   if (get_start_byte_offset () < offset)
     {
       /* THIS falls short of OFFSET.  */
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index ac8b6853f4b..d172ee756c8 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -237,6 +237,11 @@ struct bit_range
   void dump_to_pp (pretty_printer *pp) const;
   void dump () const;
 
+  bool empty_p () const
+  {
+    return m_size_in_bits == 0;
+  }
+
   bit_offset_t get_start_bit_offset () const
   {
     return m_start_bit_offset;
@@ -247,6 +252,7 @@ struct bit_range
   }
   bit_offset_t get_last_bit_offset () const
   {
+    gcc_assert (!empty_p ());
     return get_next_bit_offset () - 1;
   }
 
@@ -297,6 +303,11 @@ struct byte_range
   void dump_to_pp (pretty_printer *pp) const;
   void dump () const;
 
+  bool empty_p () const
+  {
+    return m_size_in_bytes == 0;
+  }
+
   bool contains_p (byte_offset_t offset) const
   {
     return (offset >= get_start_byte_offset ()
@@ -329,6 +340,7 @@ struct byte_range
   }
   byte_offset_t get_last_byte_offset () const
   {
+    gcc_assert (!empty_p ());
     return m_start_byte_offset + m_size_in_bytes - 1;
   }
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-zero.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-zero.c
new file mode 100644
index 00000000000..201ca00ebdb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-zero.c
@@ -0,0 +1,67 @@
+/* { dg-additional-options "-Wno-stringop-overflow"} */
+/* -Wstringop-overflow= triggers on test5.  */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+void test1 (void)
+{
+  int32_t buf[1];
+  /* Zero bytes written on non-zero allocation.  */
+  __builtin_memset (buf, 0, 0);
+}
+
+void test2 (void)
+{
+  /* ISO C forbids zero-size arrays but GCC compiles this to an
+     zero-sized array without -Wpedantic.  */
+  int32_t buf[0];
+  /* Write on zero capacity.  */
+  __builtin_memset (buf, 0, sizeof (int32_t)); /* { dg-line test2 } */
+
+  /* { dg-warning "overflow" "warning" { target *-*-* } test2 } */
+  /* { dg-message "from byte 0 till byte 3" "final event" { target *-*-* } test2 } */
+}
+
+void test3 (void)
+{
+  int32_t buf[0];
+  /* Zero bytes written on zero capacity.  */
+  __builtin_memset (buf, 0, 0);
+}
+
+void test4 (void)
+{
+  int32_t *buf = malloc (sizeof (int32_t));
+  if (!buf)
+    return;
+
+  /* Zero bytes written on non-zero allocation.  */
+  __builtin_memset (buf, 0, 0);
+  free (buf);
+}
+
+void test5 (void)
+{
+  int32_t *buf = malloc (0);
+  if (!buf)
+    return;
+
+  /* Write on zero capacity.  */
+  __builtin_memset (buf, 0, sizeof (int32_t)); /* { dg-line test5 } */
+  free (buf);
+
+  /* { dg-warning "overflow" "warning" { target *-*-* } test5 } */
+  /* { dg-message "from byte 0 till byte 3" "final event" { target *-*-* } test5 } */
+}
+
+void test6 (void)
+{
+  int32_t *buf = malloc (0);
+  if (!buf)
+    return;
+
+  /* Zero bytes written on zero capacity.  */
+  __builtin_memset (buf, 0, 0);
+  free (buf);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr106845.c b/gcc/testsuite/gcc.dg/analyzer/pr106845.c
new file mode 100644
index 00000000000..528c7b3ea9a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr106845.c
@@ -0,0 +1,11 @@
+int buf_size;
+
+int
+main (void)
+{
+  char buf[buf_size];
+
+  __builtin_memset (&buf[1], 0, buf_size);
+
+  return 0;
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-09-11 22:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-11 22:02 [gcc r13-2582] analyzer: consider empty ranges and zero byte accesses [PR106845] Tim Lange

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).