From 0d1b4edc5fff834e8f924b20dd021ded7a21d2d2 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 24 Aug 2020 09:33:42 -0400 Subject: [PATCH] analyzer: fix ICE on RANGE_EXPR in CONSTRUCTORs [PR96763] 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 | 129 +++++++++++++++++------- gcc/analyzer/store.h | 8 ++ gcc/testsuite/g++.dg/analyzer/pr96763.C | 13 +++ 3 files changed, 115 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/g++.dg/analyzer/pr96763.C diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index 14f7c00bde6..8890a69a6f8 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -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); } } diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index 636a9547f2c..0ac93179dc6 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -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 index 00000000000..1b29e30a8f8 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/pr96763.C @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +struct c0; + +struct md { + int c0::*jj[2]; +}; + +void +n0 () +{ + md{}; +} -- 2.30.2