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.
This commit is contained in:
David Malcolm 2020-08-24 09:33:42 -04:00
parent ecdb93224c
commit 0d1b4edc5f
3 changed files with 115 additions and 35 deletions

View 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);
}
}

View 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;
};

View File

@ -0,0 +1,13 @@
// { dg-do compile { target c++11 } }
struct c0;
struct md {
int c0::*jj[2];
};
void
n0 ()
{
md{};
}