diff options
author | David Malcolm <dmalcolm@redhat.com> | 2022-01-28 16:15:44 -0500 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2022-02-02 09:52:58 -0500 |
commit | 93e759fc18a1a4208ae2898610c55ebd8c9e25d8 (patch) | |
tree | 2749173a8a7299f75335c20705bbbbb8a8a8dccb /gcc/analyzer/region.h | |
parent | 9b4eee5fd158c4ee75d1f1000debbf5082fb9b56 (diff) | |
download | gcc-93e759fc18a1a4208ae2898610c55ebd8c9e25d8.zip gcc-93e759fc18a1a4208ae2898610c55ebd8c9e25d8.tar.gz gcc-93e759fc18a1a4208ae2898610c55ebd8c9e25d8.tar.bz2 |
analyzer: implement bit_range_region
GCC 12 has gained -Wanalyzer-use-of-uninitialized-value, and I'm
seeing various false positives from it due to region_model::get_lvalue
not properly handling BIT_FIELD_REF, and falling back to
using an UNKNOWN_REGION for them.
This patch fixes these false positives by implementing a new
bit_range_region region subclass for handling BIT_FIELD_REF.
gcc/analyzer/ChangeLog:
* analyzer.h (class bit_range_region): New forward decl.
* region-model-manager.cc (region_model_manager::get_bit_range):
New.
(region_model_manager::log_stats): Handle m_bit_range_regions.
* region-model.cc (region_model::get_lvalue_1): Handle
BIT_FIELD_REF.
* region-model.h (region_model_manager::get_bit_range): New decl.
(region_model_manager::m_bit_range_regions): New field.
* region.cc (region::get_base_region): Handle RK_BIT_RANGE.
(region::base_region_p): Likewise.
(region::calc_offset): Likewise.
(bit_range_region::dump_to_pp): New.
(bit_range_region::get_byte_size): New.
(bit_range_region::get_bit_size): New.
(bit_range_region::get_byte_size_sval): New.
(bit_range_region::get_relative_concrete_offset): New.
* region.h (enum region_kind): Add RK_BIT_RANGE.
(region::dyn_cast_bit_range_region): New vfunc.
(class bit_range_region): New.
(is_a_helper <const bit_range_region *>::test): New.
(default_hash_traits<bit_range_region::key_t>): New.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/torture/uninit-bit-field-ref.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/analyzer/region.h')
-rw-r--r-- | gcc/analyzer/region.h | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h index 20eca52..206b157 100644 --- a/gcc/analyzer/region.h +++ b/gcc/analyzer/region.h @@ -60,6 +60,7 @@ enum region_kind RK_HEAP_ALLOCATED, RK_ALLOCA, RK_STRING, + RK_BIT_RANGE, RK_UNKNOWN }; @@ -88,6 +89,7 @@ enum region_kind heap_allocated_region (RK_HEAP_ALLOCATED) alloca_region (RK_ALLOCA) string_region (RK_STRING) + bit_range_region (RK_BIT_RANGE) unknown_region (RK_UNKNOWN). */ /* Abstract base class for representing ways of accessing chunks of memory. @@ -127,6 +129,8 @@ public: dyn_cast_cast_region () const { return NULL; } virtual const string_region * dyn_cast_string_region () const { return NULL; } + virtual const bit_range_region * + dyn_cast_bit_range_region () const { return NULL; } virtual void accept (visitor *v) const; @@ -1133,6 +1137,91 @@ is_a_helper <const string_region *>::test (const region *reg) namespace ana { +/* A region for a specific range of bits within another region. */ + +class bit_range_region : public region +{ +public: + /* A support class for uniquifying instances of bit_range_region. */ + struct key_t + { + key_t (const region *parent, tree type, const bit_range &bits) + : m_parent (parent), m_type (type), m_bits (bits) + { + gcc_assert (parent); + } + + hashval_t hash () const + { + inchash::hash hstate; + hstate.add_ptr (m_parent); + hstate.add_ptr (m_type); + hstate.add (&m_bits, sizeof (m_bits)); + return hstate.end (); + } + + bool operator== (const key_t &other) const + { + return (m_parent == other.m_parent + && m_type == other.m_type + && m_bits == other.m_bits); + } + + void mark_deleted () { m_parent = reinterpret_cast<const region *> (1); } + void mark_empty () { m_parent = NULL; } + bool is_deleted () const + { + return m_parent == reinterpret_cast<const region *> (1); + } + bool is_empty () const { return m_parent == NULL; } + + const region *m_parent; + tree m_type; + bit_range m_bits; + }; + + bit_range_region (unsigned id, const region *parent, tree type, + const bit_range &bits) + : region (complexity (parent), id, parent, type), + m_bits (bits) + {} + + const bit_range_region * + dyn_cast_bit_range_region () const FINAL OVERRIDE { return this; } + + enum region_kind get_kind () const FINAL OVERRIDE { return RK_BIT_RANGE; } + + void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; + + const bit_range &get_bits () const { return m_bits; } + + bool get_byte_size (byte_size_t *out) const FINAL OVERRIDE; + bool get_bit_size (bit_size_t *out) const FINAL OVERRIDE; + const svalue *get_byte_size_sval (region_model_manager *mgr) const FINAL OVERRIDE; + bool get_relative_concrete_offset (bit_offset_t *out) const FINAL OVERRIDE; + +private: + bit_range m_bits; +}; + +} // namespace ana + +template <> +template <> +inline bool +is_a_helper <const bit_range_region *>::test (const region *reg) +{ + return reg->get_kind () == RK_BIT_RANGE; +} + +template <> struct default_hash_traits<bit_range_region::key_t> +: public member_function_hash_traits<bit_range_region::key_t> +{ + static const bool empty_zero_p = true; +}; + +namespace ana { + /* An unknown region, for handling unimplemented tree codes. */ class unknown_region : public region |