aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2021-08-23 14:01:01 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2021-08-23 14:01:01 -0400
commit4892b3087412e6afc261cc9977ef4b54c799660f (patch)
tree9c0804943ad79b2480c8b575b71d8bc21161e405 /gcc/analyzer
parent38757aa88735ab2e511bc428e2407a5a5e9fa0be (diff)
downloadgcc-4892b3087412e6afc261cc9977ef4b54c799660f.zip
gcc-4892b3087412e6afc261cc9977ef4b54c799660f.tar.gz
gcc-4892b3087412e6afc261cc9977ef4b54c799660f.tar.bz2
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.
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/store.cc77
-rw-r--r--gcc/analyzer/store.h5
2 files changed, 79 insertions, 3 deletions
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index eac1295..3760858 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,
+ &reg_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 b75691e..da82bd1 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;