public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-6998] analyzer: implement bit_range_region
@ 2022-02-02 14:54 David Malcolm
  0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2022-02-02 14:54 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:93e759fc18a1a4208ae2898610c55ebd8c9e25d8

commit r12-6998-g93e759fc18a1a4208ae2898610c55ebd8c9e25d8
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Fri Jan 28 16:15:44 2022 -0500

    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>

Diff:
---
 gcc/analyzer/analyzer.h                            |  1 +
 gcc/analyzer/region-model-manager.cc               | 20 +++++
 gcc/analyzer/region-model.cc                       | 14 ++++
 gcc/analyzer/region-model.h                        |  4 +
 gcc/analyzer/region.cc                             | 84 ++++++++++++++++++++
 gcc/analyzer/region.h                              | 89 ++++++++++++++++++++++
 .../gcc.dg/analyzer/torture/uninit-bit-field-ref.c | 31 ++++++++
 7 files changed, 243 insertions(+)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index c5bca2dec64..7e58bcd5d70 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -67,6 +67,7 @@ class region;
   class cast_region;
   class field_region;
   class string_region;
+  class bit_range_region;
 class region_model_manager;
 struct model_merger;
 class store_manager;
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index ba835cba22c..010ad078849 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -1494,6 +1494,25 @@ region_model_manager::get_region_for_string (tree string_cst)
   return reg;
 }
 
+/* Return the region that describes accessing BITS within PARENT as TYPE,
+   creating it if necessary.  */
+
+const region *
+region_model_manager::get_bit_range (const region *parent, tree type,
+				     const bit_range &bits)
+{
+  gcc_assert (parent);
+
+  bit_range_region::key_t key (parent, type, bits);
+  if (bit_range_region *reg = m_bit_range_regions.get (key))
+    return reg;
+
+  bit_range_region *bit_range_reg
+    = new bit_range_region (alloc_region_id (), parent, type, bits);
+  m_bit_range_regions.put (key, bit_range_reg);
+  return bit_range_reg;
+}
+
 /* If we see a tree code we don't know how to handle, rather than
    ICE or generate bogus results, create a dummy region, and notify
    CTXT so that it can mark the new state as being not properly
@@ -1663,6 +1682,7 @@ region_model_manager::log_stats (logger *logger, bool show_objs) const
   log_uniq_map (logger, show_objs, "frame_region", m_frame_regions);
   log_uniq_map (logger, show_objs, "symbolic_region", m_symbolic_regions);
   log_uniq_map (logger, show_objs, "string_region", m_string_map);
+  log_uniq_map (logger, show_objs, "bit_range_region", m_bit_range_regions);
   logger->log ("  # managed dynamic regions: %i",
 	       m_managed_dynamic_regions.length ());
   m_store_mgr.log_stats (logger, show_objs);
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 4c312b053f8..58c7028fc9c 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1707,6 +1707,20 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt) const
       }
       break;
 
+    case BIT_FIELD_REF:
+      {
+	tree inner_expr = TREE_OPERAND (expr, 0);
+	const region *inner_reg = get_lvalue (inner_expr, ctxt);
+	tree num_bits = TREE_OPERAND (expr, 1);
+	tree first_bit_offset = TREE_OPERAND (expr, 2);
+	gcc_assert (TREE_CODE (num_bits) == INTEGER_CST);
+	gcc_assert (TREE_CODE (first_bit_offset) == INTEGER_CST);
+	bit_range bits (TREE_INT_CST_LOW (first_bit_offset),
+			TREE_INT_CST_LOW (num_bits));
+	return m_mgr->get_bit_range (inner_reg, TREE_TYPE (expr), bits);
+      }
+      break;
+
     case MEM_REF:
       {
 	tree ptr = TREE_OPERAND (expr, 0);
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 983d082ab3e..3fa090d771e 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -318,6 +318,8 @@ public:
 					function *fun);
   const region *get_symbolic_region (const svalue *sval);
   const string_region *get_region_for_string (tree string_cst);
+  const region *get_bit_range (const region *parent, tree type,
+			       const bit_range &bits);
 
   const region *
   get_region_for_unexpected_tree_code (region_model_context *ctxt,
@@ -471,6 +473,8 @@ private:
   typedef hash_map<tree, string_region *> string_map_t;
   string_map_t m_string_map;
 
+  consolidation_map<bit_range_region> m_bit_range_regions;
+
   store_manager m_store_mgr;
 
   bounded_ranges_manager *m_range_mgr;
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index f5a2a0ba3df..9d8fdb22271 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -99,6 +99,7 @@ region::get_base_region () const
 	case RK_ELEMENT:
 	case RK_OFFSET:
 	case RK_SIZED:
+	case RK_BIT_RANGE:
 	  iter = iter->get_parent_region ();
 	  continue;
 	case RK_CAST:
@@ -124,6 +125,7 @@ region::base_region_p () const
     case RK_OFFSET:
     case RK_SIZED:
     case RK_CAST:
+    case RK_BIT_RANGE:
       return false;
 
     default:
@@ -547,6 +549,19 @@ region::calc_offset () const
 	  }
 	  continue;
 
+	case RK_BIT_RANGE:
+	  {
+	    const bit_range_region *bit_range_reg
+	      = (const bit_range_region *)iter_region;
+	    iter_region = iter_region->get_parent_region ();
+
+	    bit_offset_t rel_bit_offset;
+	    if (!bit_range_reg->get_relative_concrete_offset (&rel_bit_offset))
+	      return region_offset::make_symbolic (iter_region);
+	    accum_bit_offset += rel_bit_offset;
+	  }
+	  continue;
+
 	default:
 	  return region_offset::make_concrete (iter_region, accum_bit_offset);
 	}
@@ -1446,6 +1461,75 @@ string_region::dump_to_pp (pretty_printer *pp, bool simple) const
     }
 }
 
+/* class bit_range_region : public region.  */
+
+/* Implementation of region::dump_to_pp vfunc for bit_range_region.  */
+
+void
+bit_range_region::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    {
+      pp_string (pp, "BIT_RANGE_REG(");
+      get_parent_region ()->dump_to_pp (pp, simple);
+      pp_string (pp, ", ");
+      m_bits.dump_to_pp (pp);
+      pp_string (pp, ")");
+    }
+  else
+    {
+      pp_string (pp, "bit_range_region(");
+      get_parent_region ()->dump_to_pp (pp, simple);
+      pp_string (pp, ", ");
+      m_bits.dump_to_pp (pp);
+      pp_printf (pp, ")");
+    }
+}
+
+/* Implementation of region::get_byte_size vfunc for bit_range_region.  */
+
+bool
+bit_range_region::get_byte_size (byte_size_t *out) const
+{
+  if (m_bits.m_size_in_bits % BITS_PER_UNIT == 0)
+    {
+      *out = m_bits.m_size_in_bits / BITS_PER_UNIT;
+      return true;
+    }
+  return false;
+}
+
+/* Implementation of region::get_bit_size vfunc for bit_range_region.  */
+
+bool
+bit_range_region::get_bit_size (bit_size_t *out) const
+{
+  *out = m_bits.m_size_in_bits;
+  return true;
+}
+
+/* Implementation of region::get_byte_size_sval vfunc for bit_range_region.  */
+
+const svalue *
+bit_range_region::get_byte_size_sval (region_model_manager *mgr) const
+{
+  if (m_bits.m_size_in_bits % BITS_PER_UNIT != 0)
+    return mgr->get_or_create_unknown_svalue (size_type_node);
+
+  HOST_WIDE_INT num_bytes = m_bits.m_size_in_bits.to_shwi () / BITS_PER_UNIT;
+  return mgr->get_or_create_int_cst (size_type_node, num_bytes);
+}
+
+/* Implementation of region::get_relative_concrete_offset vfunc for
+   bit_range_region.  */
+
+bool
+bit_range_region::get_relative_concrete_offset (bit_offset_t *out) const
+{
+  *out = m_bits.get_start_bit_offset ();
+  return true;
+}
+
 /* class unknown_region : public region.  */
 
 /* Implementation of region::dump_to_pp vfunc for unknown_region.  */
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index 20eca524c04..206b157e908 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
diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/uninit-bit-field-ref.c b/gcc/testsuite/gcc.dg/analyzer/torture/uninit-bit-field-ref.c
new file mode 100644
index 00000000000..e2f91380a71
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/torture/uninit-bit-field-ref.c
@@ -0,0 +1,31 @@
+/* { dg-require-effective-target vect_int } */
+/* { dg-additional-options "-Wno-psabi" } */
+
+typedef __INT32_TYPE__   int32_t;
+typedef int32_t vnx4si __attribute__((vector_size (32)));
+
+extern void check_for_uninit (vnx4si v);
+
+void test_1a (vnx4si *out, int a, int b)
+{
+  vnx4si v = (vnx4si) { 1, 2, 3, 4, 5, 6, a, b };
+  check_for_uninit (v);
+}
+
+void test_1b (vnx4si *out, int a, int b)
+{
+  check_for_uninit ((vnx4si) { 1, 2, 3, 4, 5, 6, a, b });
+}
+
+static __attribute__((noipa)) void
+called_by_test_2 (vnx4si *out, int a, int b)
+{
+  *out = (vnx4si) { 1, 2, 3, 4, 5, 6, a, b };
+}
+
+void test_2 (vnx4si *out, int a, int b)
+{
+  vnx4si v;
+  called_by_test_2 (&v, a, b);
+  check_for_uninit (v);
+}


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

only message in thread, other threads:[~2022-02-02 14:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-02 14:54 [gcc r12-6998] analyzer: implement bit_range_region 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).