blob: db1521360f010b5d7e8441fcddc6bc6d19b44b00 [file]
/* Implementation of decl_region::calc_svalue_for_constructor.
Copyright (C) 2019-2026 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "analyzer/common.h"
#include "analyzer/region-model.h"
#if ENABLE_ANALYZER
namespace ana {
/* Handling of tree code CONSTRUCTOR for initialization of a decl_region. */
static bool
apply_ctor_pair_to_child_region (symbolic::concrete_bit_overlay::key &out,
const region *parent_reg,
region_model_manager *mgr,
tree index, tree val);
static bool
apply_ctor_val_to_range (symbolic::concrete_bit_overlay::key &out,
const region *parent_reg,
region_model_manager *mgr,
tree min_index, tree max_index,
tree val);
/* Get the child region of PARENT_REG based upon INDEX within a
CONSTRUCTOR. */
static const region *
get_subregion_within_ctor (const region *parent_reg, tree index,
region_model_manager *mgr)
{
switch (TREE_CODE (index))
{
default:
gcc_unreachable ();
case INTEGER_CST:
{
const svalue *index_sval
= mgr->get_or_create_constant_svalue (index);
return mgr->get_element_region (parent_reg,
TREE_TYPE (parent_reg->get_type ()),
index_sval);
}
break;
case FIELD_DECL:
return mgr->get_field_region (parent_reg, index);
}
}
/* Get the child region of PARENT_REG based upon (INDEX, VALUE) within a
CONSTRUCTOR. */
static const region *
get_subregion_within_ctor_for_ctor_pair (const region *parent_reg,
tree index,
tree value,
region_model_manager *mgr)
{
if (TREE_CODE (index) == INTEGER_CST
&& TREE_CODE (value) == RAW_DATA_CST)
{
/* Special-case; see tree.def's description of CONSTRUCTOR.
We have RAW_DATA_LENGTH of bytes, starting at INDEX's start. */
const region *start_reg
= get_subregion_within_ctor (parent_reg, index, mgr);
/* Build a bit range, relative to PARENT_REG. */
auto start_offset = start_reg->get_memory_offset (*mgr);
concrete_bit_offset conc_start_offset;
if (!concrete_from_symbolic (start_offset.get_bit_offset (),
&conc_start_offset))
return nullptr;
concrete_byte_size byte_length (RAW_DATA_LENGTH (value));
concrete_bit_size bit_length = bits_from_bytes (byte_length);
concrete_bit_range bits (conc_start_offset, bit_length);
return mgr->get_bit_range (parent_reg, NULL_TREE, bits);
}
return get_subregion_within_ctor (parent_reg, index, mgr);
}
/* Get the svalue for VAL, a non-CONSTRUCTOR value within a CONSTRUCTOR. */
static const svalue *
get_svalue_for_ctor_val (tree val, region_model_manager *mgr)
{
/* Reuse the get_rvalue logic from region_model. */
region_model m (mgr->get_node_manager ());
return m.get_rvalue (path_var (val, 0), nullptr);
}
/* Bind values from CONSTRUCTOR to OUT, relative to
PARENT_REG's relationship to its base region.
Return true if successful, false if there was a problem (e.g. due
to hitting a complexity limit). */
static bool
apply_ctor_to_region (symbolic::concrete_bit_overlay::key &out,
const region *parent_reg,
tree ctor,
region_model_manager *mgr)
{
gcc_assert (parent_reg);
gcc_assert (TREE_CODE (ctor) == CONSTRUCTOR);
unsigned ix;
tree index;
tree val;
tree parent_type = parent_reg->get_type ();
tree field;
if (TREE_CODE (parent_type) == RECORD_TYPE)
field = TYPE_FIELDS (parent_type);
else
field = NULL_TREE;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), ix, index, val)
{
if (!index)
{
/* If index is NULL, then iterate through the fields for
a RECORD_TYPE, or use an INTEGER_CST otherwise.
Compare with similar logic in output_constructor. */
if (field)
{
index = field;
field = DECL_CHAIN (field);
}
else
index = build_int_cst (integer_type_node, ix);
}
else if (TREE_CODE (index) == RANGE_EXPR)
{
tree min_index = TREE_OPERAND (index, 0);
tree max_index = TREE_OPERAND (index, 1);
if (min_index == max_index)
{
if (!apply_ctor_pair_to_child_region (out, parent_reg, mgr,
min_index, val))
return false;
}
else
{
if (!apply_ctor_val_to_range (out, parent_reg, mgr,
min_index, max_index, val))
return false;
}
continue;
}
if (!apply_ctor_pair_to_child_region (out, parent_reg, mgr, index, val))
return false;
}
return true;
}
/* Bind the value VAL into OUT at the range of elements within PARENT_REF
from MIN_INDEX to MAX_INDEX (including endpoints).
For use in handling RANGE_EXPR within a CONSTRUCTOR.
Return true if successful, false if there was a problem (e.g. due
to hitting a complexity limit). */
static bool
apply_ctor_val_to_range (symbolic::concrete_bit_overlay::key &out,
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);
auto min_element_mem_range = min_element->get_memory_range (*mgr);
auto max_element_mem_range = max_element->get_memory_range (*mgr);
gcc_assert (&min_element_mem_range.get_base_region ()
== &max_element_mem_range.get_base_region ());
symbolic_bit_range overall_sym_range
(min_element_mem_range.get_start_offset (),
(max_element_mem_range.get_next_offset ()
- min_element_mem_range.get_next_offset ()));
concrete_bit_range overall_conc_range;
if (!concrete_from_symbolic (overall_sym_range, &overall_conc_range))
return false;
/* Get the value. */
if (TREE_CODE (val) == CONSTRUCTOR)
return false;
const svalue *sval = get_svalue_for_ctor_val (val, mgr);
auto &bv_mgr = mgr->get_node_manager ().get_bit_vector_manager ();
auto &bv = bv_mgr.get_bit_vector_from_svalue (*sval);
concrete_bit_size bv_size;
if (!bv.maybe_get_concrete_size_in_bits (&bv_size))
return false;
if (overall_conc_range.get_size ().floor_mod (bv_size) != 0_bits)
return false;
auto num_repeats = overall_conc_range.get_size ().floor_div (bv_size);
auto &repeated_bv = bv_mgr.get_repeated_bits (bv, num_repeats);
out.m_concrete_range_map.insert ({overall_conc_range, repeated_bv});
return true;
}
/* Bind the value VAL into INDEX within PARENT_REF.
For use in handling a pair of entries within a CONSTRUCTOR.
Return true if successful, false if there was a problem (e.g. due
to hitting a complexity limit). */
static bool
apply_ctor_pair_to_child_region (symbolic::concrete_bit_overlay::key &out,
const region *parent_reg,
region_model_manager *mgr,
tree index, tree val)
{
const region *child_reg
= get_subregion_within_ctor_for_ctor_pair (parent_reg, index, val, mgr);
if (!child_reg)
return false;
if (TREE_CODE (val) == CONSTRUCTOR)
return apply_ctor_to_region (out, child_reg, val, mgr);
else
{
const svalue *sval = get_svalue_for_ctor_val (val, mgr);
if (child_reg->empty_p (*mgr))
return false;
auto &bv_mgr = mgr->get_node_manager ().get_bit_vector_manager ();
auto &bv = bv_mgr.get_bit_vector_from_svalue (*sval);
/* Use the size of bv rather than that of the region to cope
with flexible arrays. */
auto mem_offset = child_reg->get_memory_offset (*mgr);
symbolic_bit_range mem_range (mem_offset.get_bit_offset (),
bv.get_size ());
concrete_bit_range conc_bit_range;
if (!concrete_from_symbolic (mem_range, &conc_bit_range))
return false;
out.m_concrete_range_map.insert ({conc_bit_range, bv});
return true;
}
}
/* Implementation of decl_region::get_bit_contents_for_constructor
for when the cached value hasn't yet been calculated. */
const symbolic::bit_contents &
decl_region::calc_bit_contents_for_constructor (tree ctor,
region_model_manager *mgr) const
{
auto &node_mgr = mgr->get_node_manager ();
auto &bit_contents_mgr = node_mgr.get_bit_contents_manager ();
symbolic::concrete_bit_overlay::key bit_overlay_key
{&bit_contents_mgr.get_all_zeros (), {}};
if (!apply_ctor_to_region (bit_overlay_key, this, ctor, mgr))
return bit_contents_mgr.get_untracked ({});
return bit_contents_mgr.get_concrete_bit_overlay
(std::move (bit_overlay_key), nullptr);
}
} // namespace ana
#endif /* #if ENABLE_ANALYZER */