analyzer: fix ICE on RANGE_EXPR in CONSTRUCTORs [PR96763]
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 24 Aug 2020 13:33:42 +0000 (09:33 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Mon, 31 Aug 2020 20:07:46 +0000 (16:07 -0400)
gcc/analyzer/ChangeLog:
PR analyzer/96763
* store.cc (binding_map::apply_ctor_to_region): Handle RANGE_EXPR
by calling a new binding_map::apply_ctor_val_to_range subroutine.
Split out the existing non-CONSTRUCTOR-handling code to a new
apply_ctor_pair_to_child_region subroutine.
(binding_map::apply_ctor_val_to_range): New.
(binding_map::apply_ctor_pair_to_child_region): New, split out
from binding_map::apply_ctor_to_region as noted above.
* store.h (binding_map::apply_ctor_val_to_range): New decl.
(binding_map::apply_ctor_pair_to_child_region): New decl.

gcc/testsuite/ChangeLog:
PR analyzer/96763
* g++.dg/analyzer/pr96763.C: New test.

gcc/analyzer/store.cc
gcc/analyzer/store.h
gcc/testsuite/g++.dg/analyzer/pr96763.C [new file with mode: 0644]

index 14f7c00..8890a69 100644 (file)
@@ -419,43 +419,102 @@ binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,
     {
       if (!index)
        index = build_int_cst (integer_type_node, ix);
-      const region *child_reg
-       = get_subregion_within_ctor (parent_reg, index, mgr);
-      if (TREE_CODE (val) == CONSTRUCTOR)
-       apply_ctor_to_region (child_reg, val, mgr);
-      else
+      else if (TREE_CODE (index) == RANGE_EXPR)
        {
-         const svalue *sval = get_svalue_for_ctor_val (val, mgr);
-         const binding_key *k
-           = binding_key::make (mgr->get_store_manager (), child_reg,
-                                BK_direct);
-         /* Handle the case where we have an unknown size for child_reg
-            (e.g. due to it being a trailing field with incomplete array
-            type.  */
-         if (!k->concrete_p ())
-           {
-             /* Assume that sval has a well-defined size for this case.  */
-             tree sval_type = sval->get_type ();
-             gcc_assert (sval_type);
-             HOST_WIDE_INT sval_byte_size = int_size_in_bytes (sval_type);
-             gcc_assert (sval_byte_size != -1);
-             bit_size_t sval_bit_size = sval_byte_size * BITS_PER_UNIT;
-             /* Get offset of child relative to base region.  */
-             region_offset child_base_offset = child_reg->get_offset ();
-             gcc_assert (!child_base_offset.symbolic_p ());
-             /* Convert to an offset relative to the parent region.  */
-             region_offset parent_base_offset = parent_reg->get_offset ();
-             gcc_assert (!parent_base_offset.symbolic_p ());
-             bit_offset_t child_parent_offset
-               = (child_base_offset.get_bit_offset ()
-                  - parent_base_offset.get_bit_offset ());
-             /* Create a concrete key for the child within the parent.  */
-             k = mgr->get_store_manager ()->get_concrete_binding
-               (child_parent_offset, sval_bit_size, BK_direct);
-           }
-         gcc_assert (k->concrete_p ());
-         put (k, sval);
+         tree min_index = TREE_OPERAND (index, 0);
+         tree max_index = TREE_OPERAND (index, 1);
+         apply_ctor_val_to_range (parent_reg, mgr, min_index, max_index, val);
+         continue;
+       }
+      apply_ctor_pair_to_child_region (parent_reg, mgr, index, val);
+    }
+}
+
+/* Bind the value VAL into the range of elements within PARENT_REF
+   from MIN_INDEX to MAX_INDEX (including endpoints).
+   For use in handling RANGE_EXPR within a CONSTRUCTOR.  */
+
+void
+binding_map::apply_ctor_val_to_range (const region *parent_reg,
+                                     region_model_manager *mgr,
+                                     tree min_index, tree max_index,
+                                     tree val)
+{
+  gcc_assert (TREE_CODE (min_index) == INTEGER_CST);
+  gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
+
+  /* Generate a binding key for the range.  */
+  const region *min_element
+    = get_subregion_within_ctor (parent_reg, min_index, mgr);
+  const region *max_element
+    = get_subregion_within_ctor (parent_reg, max_index, mgr);
+  region_offset min_offset = min_element->get_offset ();
+  bit_offset_t start_bit_offset = min_offset.get_bit_offset ();
+  store_manager *smgr = mgr->get_store_manager ();
+  const binding_key *max_element_key
+    = binding_key::make (smgr, max_element, BK_direct);
+  gcc_assert (max_element_key->concrete_p ());
+  const concrete_binding *max_element_ckey
+    = max_element_key->dyn_cast_concrete_binding ();
+  bit_size_t range_size_in_bits
+    = max_element_ckey->get_next_bit_offset () - start_bit_offset;
+  const concrete_binding *range_key
+    = smgr->get_concrete_binding (start_bit_offset, range_size_in_bits,
+                                 BK_direct);
+  gcc_assert (range_key->concrete_p ());
+
+  /* Get the value.  */
+  gcc_assert (TREE_CODE (val) != CONSTRUCTOR);
+  const svalue *sval = get_svalue_for_ctor_val (val, mgr);
+
+  /* Bind the value to the range.  */
+  put (range_key, sval);
+}
+
+/* Bind the value VAL into INDEX within PARENT_REF.
+   For use in handling a pair of entries within a CONSTRUCTOR.  */
+
+void
+binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
+                                             region_model_manager *mgr,
+                                             tree index, tree val)
+{
+  const region *child_reg
+    = get_subregion_within_ctor (parent_reg, index, mgr);
+  if (TREE_CODE (val) == CONSTRUCTOR)
+    apply_ctor_to_region (child_reg, val, mgr);
+  else
+    {
+      const svalue *sval = get_svalue_for_ctor_val (val, mgr);
+      const binding_key *k
+       = binding_key::make (mgr->get_store_manager (), child_reg,
+                            BK_direct);
+      /* Handle the case where we have an unknown size for child_reg
+        (e.g. due to it being a trailing field with incomplete array
+        type.  */
+      if (!k->concrete_p ())
+       {
+         /* Assume that sval has a well-defined size for this case.  */
+         tree sval_type = sval->get_type ();
+         gcc_assert (sval_type);
+         HOST_WIDE_INT sval_byte_size = int_size_in_bytes (sval_type);
+         gcc_assert (sval_byte_size != -1);
+         bit_size_t sval_bit_size = sval_byte_size * BITS_PER_UNIT;
+         /* Get offset of child relative to base region.  */
+         region_offset child_base_offset = child_reg->get_offset ();
+         gcc_assert (!child_base_offset.symbolic_p ());
+         /* Convert to an offset relative to the parent region.  */
+         region_offset parent_base_offset = parent_reg->get_offset ();
+         gcc_assert (!parent_base_offset.symbolic_p ());
+         bit_offset_t child_parent_offset
+           = (child_base_offset.get_bit_offset ()
+              - parent_base_offset.get_bit_offset ());
+         /* Create a concrete key for the child within the parent.  */
+         k = mgr->get_store_manager ()->get_concrete_binding
+           (child_parent_offset, sval_bit_size, BK_direct);
        }
+      gcc_assert (k->concrete_p ());
+      put (k, sval);
     }
 }
 
index 636a954..0ac9317 100644 (file)
@@ -344,6 +344,14 @@ public:
                             region_model_manager *mgr);
 
 private:
+  void apply_ctor_val_to_range (const region *parent_reg,
+                               region_model_manager *mgr,
+                               tree min_index, tree max_index,
+                               tree val);
+  void apply_ctor_pair_to_child_region (const region *parent_reg,
+                                       region_model_manager *mgr,
+                                       tree index, tree val);
+
   map_t m_map;
 };
 
diff --git a/gcc/testsuite/g++.dg/analyzer/pr96763.C b/gcc/testsuite/g++.dg/analyzer/pr96763.C
new file mode 100644 (file)
index 0000000..1b29e30
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+struct c0;
+
+struct md {
+  int c0::*jj[2];
+};
+
+void
+n0 ()
+{
+  md{};
+}