public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-3093] analyzer: fix uninit false positive on overlapping bindings
@ 2021-08-23 18:06 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2021-08-23 18:06 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:4892b3087412e6afc261cc9977ef4b54c799660f
commit r12-3093-g4892b3087412e6afc261cc9977ef4b54c799660f
Author: David Malcolm <dmalcolm@redhat.com>
Date: Mon Aug 23 14:01:01 2021 -0400
analyzer: fix uninit false positive on overlapping bindings
gcc/analyzer/ChangeLog:
* store.cc (bit_range::intersects_p): New overload.
(bit_range::operator-): New.
(binding_cluster::maybe_get_compound_binding): Handle the partial
overlap case.
(selftest::test_bit_range_intersects_p): Add test coverage for
new overload of bit_range::intersects_p.
* store.h (bit_range::intersects_p): New overload.
(bit_range::operator-): New.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/data-model-22.c: New test.
* gcc.dg/analyzer/uninit-6.c: New test.
* gcc.dg/analyzer/uninit-6b.c: New test.
Diff:
---
gcc/analyzer/store.cc | 77 +++++++++++++++++++-
gcc/analyzer/store.h | 5 ++
gcc/testsuite/gcc.dg/analyzer/data-model-22.c | 101 ++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/analyzer/uninit-6.c | 29 ++++++++
gcc/testsuite/gcc.dg/analyzer/uninit-6b.c | 29 ++++++++
5 files changed, 238 insertions(+), 3 deletions(-)
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index eac1295c5de..3760858c26d 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -253,6 +253,35 @@ bit_range::contains_p (const bit_range &other, bit_range *out) const
return false;
}
+/* If OTHER intersects this, return true and write
+ the relative range of OTHER within THIS to *OUT_THIS,
+ and the relative range of THIS within OTHER to *OUT_OTHER.
+ Otherwise return false. */
+
+bool
+bit_range::intersects_p (const bit_range &other,
+ bit_range *out_this,
+ bit_range *out_other) const
+{
+ if (get_start_bit_offset () < other.get_next_bit_offset ()
+ && other.get_start_bit_offset () < get_next_bit_offset ())
+ {
+ bit_offset_t overlap_start
+ = MAX (get_start_bit_offset (),
+ 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);
+ 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 ();
+ return true;
+ }
+ else
+ return false;
+}
+
int
bit_range::cmp (const bit_range &br1, const bit_range &br2)
{
@@ -263,6 +292,14 @@ bit_range::cmp (const bit_range &br1, const bit_range &br2)
return wi::cmpu (br1.m_size_in_bits, br2.m_size_in_bits);
}
+/* Offset this range by OFFSET. */
+
+bit_range
+bit_range::operator- (bit_offset_t offset) const
+{
+ return bit_range (m_start_bit_offset - offset, m_size_in_bits);
+}
+
/* If MASK is a contiguous range of set bits, write them
to *OUT and return true.
Otherwise return false. */
@@ -1570,9 +1607,29 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
}
else
{
- /* REG and the bound range partially overlap.
- We don't handle this case yet. */
- return NULL;
+ /* REG and the bound range partially overlap. */
+ bit_range reg_subrange (0, 0);
+ bit_range bound_subrange (0, 0);
+ reg_range.intersects_p (bound_range,
+ ®_subrange, &bound_subrange);
+
+ /* Get the bits from the bound value for the bits at the
+ intersection (relative to the bound value). */
+ const svalue *overlap_sval
+ = sval->extract_bit_range (NULL_TREE,
+ bound_subrange,
+ mgr->get_svalue_manager ());
+
+ /* Get key for overlap, relative to the REG. */
+ const concrete_binding *overlap_concrete_key
+ = mgr->get_concrete_binding (reg_subrange);
+ result_map.put (overlap_concrete_key, overlap_sval);
+
+ /* Clobber default_map, removing/trimming/spliting where
+ it overlaps with overlap_concrete_key. */
+ default_map.remove_overlapping_bindings (mgr,
+ overlap_concrete_key,
+ NULL);
}
}
else
@@ -2905,6 +2962,20 @@ test_bit_range_intersects_p ()
ASSERT_FALSE (b3_to_5.intersects_p (b6_to_7));
ASSERT_FALSE (b6_to_7.intersects_p (b3_to_5));
+
+ bit_range r1 (0,0);
+ bit_range r2 (0,0);
+ ASSERT_TRUE (b1_to_6.intersects_p (b0_to_7, &r1, &r2));
+ ASSERT_EQ (r1.get_start_bit_offset (), 0);
+ ASSERT_EQ (r1.m_size_in_bits, 6);
+ ASSERT_EQ (r2.get_start_bit_offset (), 1);
+ ASSERT_EQ (r2.m_size_in_bits, 6);
+
+ ASSERT_TRUE (b0_to_7.intersects_p (b1_to_6, &r1, &r2));
+ ASSERT_EQ (r1.get_start_bit_offset (), 1);
+ ASSERT_EQ (r1.m_size_in_bits, 6);
+ ASSERT_EQ (r2.get_start_bit_offset (), 0);
+ ASSERT_EQ (r2.m_size_in_bits, 6);
}
/* Implementation detail of ASSERT_BIT_RANGE_FROM_MASK_EQ. */
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index b75691e4a16..da82bd1bdec 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -269,9 +269,14 @@ struct bit_range
return (get_start_bit_offset () < other.get_next_bit_offset ()
&& other.get_start_bit_offset () < get_next_bit_offset ());
}
+ bool intersects_p (const bit_range &other,
+ bit_range *out_this,
+ bit_range *out_other) const;
static int cmp (const bit_range &br1, const bit_range &br2);
+ bit_range operator- (bit_offset_t offset) const;
+
static bool from_mask (unsigned HOST_WIDE_INT mask, bit_range *out);
bool as_byte_range (byte_range *out) const;
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-22.c b/gcc/testsuite/gcc.dg/analyzer/data-model-22.c
new file mode 100644
index 00000000000..8429b2f4dc6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-22.c
@@ -0,0 +1,101 @@
+#include <string.h>
+#include "analyzer-decls.h"
+
+extern void check_init_char (char v);
+extern void check_init_int (int v);
+
+void test_1 (void)
+{
+ union
+ {
+ char c[16];
+ int i[4];
+ } v;
+ memset (&v, 0, sizeof (v));
+ v.c[5] = 42;
+ check_init_int (v.c[0]);
+ check_init_int (v.c[4]);
+ check_init_int (v.c[6]);
+ check_init_int (v.i[1]);
+}
+
+void test_2 (void)
+{
+ /* Intersection of byte ranges within "v". */
+ union
+ {
+ struct {
+ int a;
+ char b;
+ char c;
+ } __attribute__((packed)) icc;
+ struct {
+ char a;
+ int b;
+ char c;
+ } __attribute__((packed)) cic;
+ struct {
+ char a;
+ char b;
+ int c;
+ } __attribute__((packed)) cci;
+ } v;
+
+ v.icc.a = 1066;
+ v.icc.b = 42;
+ v.icc.c = 17;
+
+ __analyzer_eval (v.icc.a == 1066); /* { dg-warning "TRUE" } */
+ __analyzer_eval (v.icc.b == 42); /* { dg-warning "TRUE" } */
+ __analyzer_eval (v.icc.c == 17); /* { dg-warning "TRUE" } */
+ check_init_int (v.icc.a);
+ check_init_char (v.icc.b);
+ check_init_char (v.icc.c);
+
+ check_init_char (v.cic.a);
+ check_init_int (v.cic.b);
+ check_init_char (v.cic.c);
+
+ check_init_char (v.cci.a);
+ check_init_char (v.cci.b);
+ check_init_int (v.cci.c);
+
+ v.cic.a = 42;
+ v.cic.b = 1066;
+ v.cic.c = 17;
+
+ __analyzer_eval (v.cic.a == 42); /* { dg-warning "TRUE" } */
+ __analyzer_eval (v.cic.b == 1066); /* { dg-warning "TRUE" } */
+ __analyzer_eval (v.cic.c == 17); /* { dg-warning "TRUE" } */
+ check_init_int (v.icc.a);
+ check_init_char (v.icc.b);
+ check_init_char (v.icc.c);
+
+ check_init_char (v.cic.a);
+ check_init_int (v.cic.b);
+ check_init_char (v.cic.c);
+
+ check_init_char (v.cci.a);
+ check_init_char (v.cci.b);
+ check_init_int (v.cci.c);
+
+ v.cci.a = 42;
+ v.cci.b = 17;
+ v.cci.c = 1066;
+
+ __analyzer_eval (v.cci.a == 42); /* { dg-warning "TRUE" } */
+ __analyzer_eval (v.cci.b == 17); /* { dg-warning "TRUE" } */
+ __analyzer_eval (v.cci.c == 1066); /* { dg-warning "TRUE" } */
+ check_init_int (v.icc.a);
+ check_init_char (v.icc.b);
+ check_init_char (v.icc.c);
+
+ check_init_char (v.cic.a);
+ check_init_int (v.cic.b);
+ check_init_char (v.cic.c);
+
+ check_init_char (v.cci.a);
+ check_init_char (v.cci.b);
+ check_init_int (v.cci.c);
+
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-6.c b/gcc/testsuite/gcc.dg/analyzer/uninit-6.c
new file mode 100644
index 00000000000..75a99ad2c44
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/uninit-6.c
@@ -0,0 +1,29 @@
+/* Reduced from uninit false positive seen on Linux kernel with
+ net/ethtool/ioctl.c */
+
+typedef signed char s8;
+typedef unsigned int u32;
+typedef __SIZE_TYPE__ size_t;
+
+void *memset(void *s, int c, size_t n);
+
+struct ethtool_link_settings {
+ u32 cmd;
+ s8 link_mode_masks_nwords;
+};
+
+struct ethtool_link_ksettings {
+ struct ethtool_link_settings base;
+ u32 lanes;
+};
+
+struct ethtool_link_settings
+ethtool_get_link_ksettings(void) {
+ struct ethtool_link_ksettings link_ksettings;
+
+ memset(&link_ksettings, 0, sizeof(link_ksettings));
+ link_ksettings.base.cmd = 0x0000004c;
+ link_ksettings.base.link_mode_masks_nwords = -3;
+
+ return link_ksettings.base;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-6b.c b/gcc/testsuite/gcc.dg/analyzer/uninit-6b.c
new file mode 100644
index 00000000000..32ba30fb384
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/uninit-6b.c
@@ -0,0 +1,29 @@
+/* Reduced from uninit false positive seen on Linux kernel with
+ net/ethtool/ioctl.c */
+
+typedef signed char s8;
+typedef unsigned int u32;
+typedef __SIZE_TYPE__ size_t;
+
+void *memset(void *s, int c, size_t n);
+
+struct ethtool_link_settings {
+ u32 cmd;
+ s8 link_mode_masks_nwords;
+};
+
+struct ethtool_link_ksettings {
+ u32 lanes;
+ struct ethtool_link_settings base;
+};
+
+struct ethtool_link_settings
+ethtool_get_link_ksettings(void) {
+ struct ethtool_link_ksettings link_ksettings;
+
+ memset(&link_ksettings, 0, sizeof(link_ksettings));
+ link_ksettings.base.cmd = 0x0000004c;
+ link_ksettings.base.link_mode_masks_nwords = -3;
+
+ return link_ksettings.base;
+}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2021-08-23 18:06 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-23 18:06 [gcc r12-3093] analyzer: fix uninit false positive on overlapping bindings David Malcolm
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).