mirror of git://gcc.gnu.org/git/gcc.git
analyzer: reimplement binding_map using a "spatial" representation
Previously, ana::binding_map was a hash_map <const binding_key *, const svalue *> combining both concrete and symbolic keys into the same map, with no meaningful ordering. This patch reimplements it as: concrete_bindings_t m_concrete; symbolic_bindings_t m_symbolic; where concrete_bindings_t is: std::map<bit_range, const svalue *> thus organizing them into order, and symbolic_bindings_t is: std::vector<symbolic_binding> where a symbolic_binding is a (region, svalue pair) and the vector for now has at most one symbolic binding. In particular, this means that iterating over the bindings in a map or cluster yields them in ascending memory order of concrete bindings, followed by the symbolic binding (if present). This should allow various optimizations, make it easier to detect overlapping bindings, and to eventually better support analyzing code that builds up a string via concatenations (perhaps with multiple symbolic bindings "hanging off the end"). gcc/analyzer/ChangeLog: * access-diagram.cc: Update for renaming of fields of binding_key. * ana-state-to-diagnostic-state.cc: Likewise. * bounds-checking.cc: Likewise. Add store_manager param. * call-summary.cc: Likewise. * diagnostic-manager.cc: Drop includes of "basic-block.h" and "gimple.h". * engine.cc: Likewise. * infinite-recursion.cc: Update for renaming of fields of binding_key. * kf.cc: Pass store_manager to mark_as_escaped. * program-state.cc: Update for renaming of fields of binding_key. * region-model-asm.cc: Pass store manager to get_or_create_cluster. * region-model-reachability.cc: Likewise. Update for renaming of fields of binding_key. * region-model.cc: Likewise. (struct bad_pointer_finder): Drop. (region_model::poison_any_pointers_to_descendents): Implement iteration directly, rather than using store::for_each_binding. Drop return value. (selftest::test_struct): Set field in order y then x. Verify that iteration yields bindings in order x then y. * region-model.h (region_model::poison_any_pointers_to_descendents): Drop return value. * region.cc: Pass store manager to get_or_create_cluster. * store.cc (binding_map::const_iterator::operator==): New. (binding_map::const_iterator::operator++): New. (binding_map::const_iterator::operator*): New. (binding_map::iterator::operator==): New. (binding_map::iterator::operator++): New. (binding_map::iterator::operator*): New. (binding_map::binding_map): Reimplement. (binding_map::operator=): Reimplement. (binding_map::operator==): Reimplement. (binding_map::hash): Reimplement. (binding_map::get): Reimplement. (binding_map::put): Reimplement. (binding_map::overwrite): New. (binding_map::remove): New. (binding_map::begin): New. (binding_map::end): New. (binding_map::elements): New. (binding_map::dump_to_pp): Reimplement. (binding_map::to_json): Iterate over *this directly; drop sort. (binding_map::add_to_tree_widget): Likewise. (binding_map::cmp): Reimplement. (binding_map::get_overlapping_bindings): Update for field renamings. (binding_cluster::binding_cluster): Add store_mgr param. (binding_cluster::validate): Update for field renamings. (binding_cluster::bind_compound_sval): Likewise. (binding_cluster::purge_state_involving): Likewise. (binding_cluster::maybe_get_compound_binding): Likewise. Add store_mgr param. (binding_cluster::can_merge_p): Likewise. Update for new implementation. (binding_cluster::make_unknown_relative_to): Likewise. (binding_cluster::on_unknown_fncall): Likewise. (binding_cluster::on_asm): Likewise. (binding_cluster::get_representative_path_vars): Likewise. (store::set_value): Likewise. (store::on_maybe_live_values): Pass around store_manager. (store::fill_region): Likewise. (store::mark_region_as_unknown): Likewise. (store::get_or_create_cluster): Likewise. (store::can_merge_p): Likewise. (store::mark_as_escaped): Likewise. (store::canonicalize): Update for field renamings. (store::loop_replay_fixup): Likewise. Pass around store_manager. (store::replay_call_summary_cluster): Likewise. (selftest::test_binding_map_ops): New. (selftest::analyzer_store_cc_tests): Call it. * store.h (class binding_map): Reimplement. (binding_map::map_t): Drop. (struct binding_map::symbolic_binding): New. (binding_map::concrete_bindings_t): New. (binding_map::symbolic_bindings_t): New. (struct binding_map::bindings_pair): New. (class binding_map::const_iterator): New. (class binding_map::iterator): New. (binding_map::get): Reimplement. (binding_map::overwrite): New decl. (binding_map::remove): Reimplement. (binding_map::clear): Reimplement. (binding_map::put): Reimplement. (binding_map::empty_p): Reimplement. (binding_map::begin): Reimplement. (binding_map::end): Reimplement. (binding_map::elements): Reimplement. (binding_map::m_map): Drop field. (binding_map::m_store_mgr): New field. (binding_map::m_concrete): New field. (binding_map::m_symbolic): New field. (BindingVisitor): Drop. (binding_cluster::map_t): Drop. (binding_cluster::iterator_t): Reimplement. (binding_cluster::const_iterator_t): New. (binding_cluster::binding_cluster): Add store_mgr param. (binding_cluster::for_each_value): Reimplement. (binding_cluster::empty_p): Reimplement. (binding_cluster::for_each_binding): Drop. (binding_cluster::begin): Split into const/non-const overloads. (binding_cluster::get_map): Add non-const overload. (store::get_or_create_cluster): Add store_mgr param. (store::mark_as_escaped): Likewise. (store::for_each_binding): Drop. (store::on_maybe_live_values): Add store_mgr param. * svalue.cc (compound_svalue::compound_svalue): Reimplement. (compound_svalue::accept): Likewise. (compound_svalue::calc_complexity): Likewise. (compound_svalue::maybe_fold_bits_within): Likewise. * svalue.h (compound_svalue::const_iterator_t): New. (compound_svalue::begin): Split into const/non-const overloads. (compound_svalue::end): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/plugin/analyzer_cpython_plugin.cc: Replace INCLUDE_ defines with include of include "analyzer/common.h". Update for changes to binding_pair. * gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise. * gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
parent
ccb2a10820
commit
310a70ef6d
|
@ -1216,8 +1216,8 @@ public:
|
||||||
auto_vec <const binding_key *> binding_keys;
|
auto_vec <const binding_key *> binding_keys;
|
||||||
for (auto iter : map)
|
for (auto iter : map)
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
const svalue *bound_sval = iter.second;
|
const svalue *bound_sval = iter.m_sval;
|
||||||
if (const concrete_binding *concrete_key
|
if (const concrete_binding *concrete_key
|
||||||
= key->dyn_cast_concrete_binding ())
|
= key->dyn_cast_concrete_binding ())
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,7 +86,7 @@ analyzer_state_graph::analyzer_state_graph (const program_state &state,
|
||||||
for (auto cluster_iter : *state.m_region_model->get_store ())
|
for (auto cluster_iter : *state.m_region_model->get_store ())
|
||||||
for (auto binding_iter : *cluster_iter.second)
|
for (auto binding_iter : *cluster_iter.second)
|
||||||
{
|
{
|
||||||
const svalue *svalue = binding_iter.second;
|
const svalue *svalue = binding_iter.m_sval;
|
||||||
if (const region *reg = svalue->maybe_get_region ())
|
if (const region *reg = svalue->maybe_get_region ())
|
||||||
if (svalue->get_type () && !reg->get_type ())
|
if (svalue->get_type () && !reg->get_type ())
|
||||||
{
|
{
|
||||||
|
@ -417,8 +417,8 @@ create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
|
||||||
concrete_bindings_t conc_bindings;
|
concrete_bindings_t conc_bindings;
|
||||||
for (auto iter : cluster)
|
for (auto iter : cluster)
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
const svalue *svalue = iter.second;
|
const svalue *svalue = iter.m_sval;
|
||||||
if (auto conc_key = key->dyn_cast_concrete_binding ())
|
if (auto conc_key = key->dyn_cast_concrete_binding ())
|
||||||
conc_bindings[conc_key->get_bit_range ()] = svalue;
|
conc_bindings[conc_key->get_bit_range ()] = svalue;
|
||||||
if (const region *reg = svalue->maybe_get_region ())
|
if (const region *reg = svalue->maybe_get_region ())
|
||||||
|
|
|
@ -1334,11 +1334,11 @@ strip_types (const svalue *sval,
|
||||||
case SK_COMPOUND:
|
case SK_COMPOUND:
|
||||||
{
|
{
|
||||||
const compound_svalue *compound_sval = (const compound_svalue *)sval;
|
const compound_svalue *compound_sval = (const compound_svalue *)sval;
|
||||||
binding_map typeless_map;
|
binding_map typeless_map (*mgr.get_store_manager ());
|
||||||
for (auto iter : compound_sval->get_map ())
|
for (auto iter : compound_sval->get_map ())
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
const svalue *bound_sval = iter.second;
|
const svalue *bound_sval = iter.m_sval;
|
||||||
typeless_map.put (key, strip_types (bound_sval, mgr));
|
typeless_map.put (key, strip_types (bound_sval, mgr));
|
||||||
}
|
}
|
||||||
return mgr.get_or_create_compound_svalue (NULL_TREE, typeless_map);
|
return mgr.get_or_create_compound_svalue (NULL_TREE, typeless_map);
|
||||||
|
|
|
@ -422,10 +422,10 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
|
||||||
= as_a <const compound_svalue *> (summary_sval);
|
= as_a <const compound_svalue *> (summary_sval);
|
||||||
region_model_manager *mgr = get_manager ();
|
region_model_manager *mgr = get_manager ();
|
||||||
store_manager *store_mgr = mgr->get_store_manager ();
|
store_manager *store_mgr = mgr->get_store_manager ();
|
||||||
binding_map caller_map;
|
binding_map caller_map (*store_mgr);
|
||||||
auto_vec <const binding_key *> summary_keys;
|
auto_vec <const binding_key *> summary_keys;
|
||||||
for (auto kv : *compound_summary_sval)
|
for (auto kv : *compound_summary_sval)
|
||||||
summary_keys.safe_push (kv.first);
|
summary_keys.safe_push (kv.m_key);
|
||||||
summary_keys.qsort (binding_key::cmp_ptrs);
|
summary_keys.qsort (binding_key::cmp_ptrs);
|
||||||
for (auto key : summary_keys)
|
for (auto key : summary_keys)
|
||||||
{
|
{
|
||||||
|
@ -447,8 +447,8 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
|
||||||
for (auto inner_kv : *inner_compound_sval)
|
for (auto inner_kv : *inner_compound_sval)
|
||||||
{
|
{
|
||||||
// These should already be mapped to the caller.
|
// These should already be mapped to the caller.
|
||||||
const binding_key *inner_key = inner_kv.first;
|
const binding_key *inner_key = inner_kv.m_key;
|
||||||
const svalue *inner_sval = inner_kv.second;
|
const svalue *inner_sval = inner_kv.m_sval;
|
||||||
gcc_assert (inner_key->concrete_p ());
|
gcc_assert (inner_key->concrete_p ());
|
||||||
const concrete_binding *concrete_key
|
const concrete_binding *concrete_key
|
||||||
= as_a <const concrete_binding *> (inner_key);
|
= as_a <const concrete_binding *> (inner_key);
|
||||||
|
|
|
@ -21,8 +21,6 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "analyzer/common.h"
|
#include "analyzer/common.h"
|
||||||
|
|
||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
#include "basic-block.h"
|
|
||||||
#include "gimple.h"
|
|
||||||
#include "gimple-pretty-print.h"
|
#include "gimple-pretty-print.h"
|
||||||
#include "gimple-iterator.h"
|
#include "gimple-iterator.h"
|
||||||
#include "inlining-iterator.h"
|
#include "inlining-iterator.h"
|
||||||
|
|
|
@ -23,9 +23,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
#include "basic-block.h"
|
|
||||||
#include "gcc-rich-location.h"
|
#include "gcc-rich-location.h"
|
||||||
#include "gimple.h"
|
|
||||||
#include "gimple-iterator.h"
|
#include "gimple-iterator.h"
|
||||||
#include "gimple-pretty-print.h"
|
#include "gimple-pretty-print.h"
|
||||||
#include "cgraph.h"
|
#include "cgraph.h"
|
||||||
|
|
|
@ -401,7 +401,7 @@ contains_unknown_p (const svalue *sval)
|
||||||
if (const compound_svalue *compound_sval
|
if (const compound_svalue *compound_sval
|
||||||
= sval->dyn_cast_compound_svalue ())
|
= sval->dyn_cast_compound_svalue ())
|
||||||
for (auto iter : *compound_sval)
|
for (auto iter : *compound_sval)
|
||||||
if (iter.second->get_kind () == SK_UNKNOWN)
|
if (iter.m_sval->get_kind () == SK_UNKNOWN)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -857,7 +857,8 @@ public:
|
||||||
const svalue *ptr_sval = cd.get_arg_svalue (0);
|
const svalue *ptr_sval = cd.get_arg_svalue (0);
|
||||||
const region *reg
|
const region *reg
|
||||||
= model->deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
|
= model->deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
|
||||||
model->get_store ()->mark_as_escaped (reg);
|
store_manager *store_mgr = model->get_manager ()->get_store_manager ();
|
||||||
|
model->get_store ()->mark_as_escaped (*store_mgr, reg);
|
||||||
enum memory_space mem_space = reg->get_memory_space ();
|
enum memory_space mem_space = reg->get_memory_space ();
|
||||||
switch (mem_space)
|
switch (mem_space)
|
||||||
{
|
{
|
||||||
|
|
|
@ -564,7 +564,7 @@ sm_state_map::impl_set_state (const svalue *sval,
|
||||||
= sval->dyn_cast_compound_svalue ())
|
= sval->dyn_cast_compound_svalue ())
|
||||||
for (auto iter : *compound_sval)
|
for (auto iter : *compound_sval)
|
||||||
{
|
{
|
||||||
const svalue *inner_sval = iter.second;
|
const svalue *inner_sval = iter.m_sval;
|
||||||
if (inner_sval->can_have_associated_state_p ())
|
if (inner_sval->can_have_associated_state_p ())
|
||||||
impl_set_state (inner_sval, state, origin, ext_state);
|
impl_set_state (inner_sval, state, origin, ext_state);
|
||||||
}
|
}
|
||||||
|
@ -1531,7 +1531,7 @@ program_state::can_purge_base_region_p (const extrinsic_state &ext_state,
|
||||||
|
|
||||||
for (auto iter : *cluster)
|
for (auto iter : *cluster)
|
||||||
{
|
{
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.m_sval;
|
||||||
if (!can_purge_p (ext_state, sval))
|
if (!can_purge_p (ext_state, sval))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,7 +260,9 @@ region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt)
|
||||||
|| !base_reg->tracked_p ())
|
|| !base_reg->tracked_p ())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
binding_cluster *cluster = m_store.get_or_create_cluster (base_reg);
|
binding_cluster *cluster
|
||||||
|
= m_store.get_or_create_cluster (*m_mgr->get_store_manager (),
|
||||||
|
base_reg);
|
||||||
cluster->on_asm (stmt, m_mgr->get_store_manager (),
|
cluster->on_asm (stmt, m_mgr->get_store_manager (),
|
||||||
conjured_purge (this, ctxt));
|
conjured_purge (this, ctxt));
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,10 +169,10 @@ reachable_regions::handle_sval (const svalue *sval)
|
||||||
if (const compound_svalue *compound_sval
|
if (const compound_svalue *compound_sval
|
||||||
= sval->dyn_cast_compound_svalue ())
|
= sval->dyn_cast_compound_svalue ())
|
||||||
{
|
{
|
||||||
for (compound_svalue::iterator_t iter = compound_sval->begin ();
|
for (auto iter = compound_sval->begin ();
|
||||||
iter != compound_sval->end (); ++iter)
|
iter != compound_sval->end (); ++iter)
|
||||||
{
|
{
|
||||||
const svalue *iter_sval = (*iter).second;
|
const svalue *iter_sval = (*iter).m_sval;
|
||||||
handle_sval (iter_sval);
|
handle_sval (iter_sval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,10 +235,10 @@ reachable_regions::handle_parm (const svalue *sval, tree param_type)
|
||||||
if (const compound_svalue *compound_sval
|
if (const compound_svalue *compound_sval
|
||||||
= sval->dyn_cast_compound_svalue ())
|
= sval->dyn_cast_compound_svalue ())
|
||||||
{
|
{
|
||||||
for (compound_svalue::iterator_t iter = compound_sval->begin ();
|
for (auto iter = compound_sval->begin ();
|
||||||
iter != compound_sval->end (); ++iter)
|
iter != compound_sval->end (); ++iter)
|
||||||
{
|
{
|
||||||
const svalue *iter_sval = (*iter).second;
|
const svalue *iter_sval = (*iter).m_sval;
|
||||||
handle_sval (iter_sval);
|
handle_sval (iter_sval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,8 @@ reachable_regions::mark_escaped_clusters (region_model_context *ctxt)
|
||||||
iter != m_mutable_base_regs.end (); ++iter)
|
iter != m_mutable_base_regs.end (); ++iter)
|
||||||
{
|
{
|
||||||
const region *base_reg = *iter;
|
const region *base_reg = *iter;
|
||||||
m_store->mark_as_escaped (base_reg);
|
store_manager *store_mgr = m_model->get_manager ()->get_store_manager ();
|
||||||
|
m_store->mark_as_escaped (*store_mgr, base_reg);
|
||||||
|
|
||||||
/* If we have a function that's escaped, potentially add
|
/* If we have a function that's escaped, potentially add
|
||||||
it to the worklist. */
|
it to the worklist. */
|
||||||
|
|
|
@ -4495,8 +4495,8 @@ public:
|
||||||
return;
|
return;
|
||||||
for (auto iter : *cluster)
|
for (auto iter : *cluster)
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.m_sval;
|
||||||
|
|
||||||
if (const concrete_binding *concrete_key
|
if (const concrete_binding *concrete_key
|
||||||
= key->dyn_cast_concrete_binding ())
|
= key->dyn_cast_concrete_binding ())
|
||||||
|
@ -4696,7 +4696,7 @@ region_model::scan_for_null_terminator_1 (const region *reg,
|
||||||
logger->end_log_line ();
|
logger->end_log_line ();
|
||||||
}
|
}
|
||||||
|
|
||||||
binding_map result;
|
binding_map result (*store_mgr);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -5118,7 +5118,8 @@ region_model::mark_region_as_unknown (const region *reg,
|
||||||
svalue_set maybe_live_values;
|
svalue_set maybe_live_values;
|
||||||
m_store.mark_region_as_unknown (m_mgr->get_store_manager(), reg,
|
m_store.mark_region_as_unknown (m_mgr->get_store_manager(), reg,
|
||||||
uncertainty, &maybe_live_values);
|
uncertainty, &maybe_live_values);
|
||||||
m_store.on_maybe_live_values (maybe_live_values);
|
m_store.on_maybe_live_values (*m_mgr->get_store_manager (),
|
||||||
|
maybe_live_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine what is known about the condition "LHS_SVAL OP RHS_SVAL" within
|
/* Determine what is known about the condition "LHS_SVAL OP RHS_SVAL" within
|
||||||
|
@ -6733,7 +6734,8 @@ region_model::on_top_level_param (tree param,
|
||||||
const svalue *init_ptr_sval
|
const svalue *init_ptr_sval
|
||||||
= m_mgr->get_or_create_initial_value (param_reg);
|
= m_mgr->get_or_create_initial_value (param_reg);
|
||||||
const region *pointee_reg = m_mgr->get_symbolic_region (init_ptr_sval);
|
const region *pointee_reg = m_mgr->get_symbolic_region (init_ptr_sval);
|
||||||
m_store.mark_as_escaped (pointee_reg);
|
store_manager *store_mgr = m_mgr->get_store_manager ();
|
||||||
|
m_store.mark_as_escaped (*store_mgr, pointee_reg);
|
||||||
if (nonnull)
|
if (nonnull)
|
||||||
{
|
{
|
||||||
const svalue *null_ptr_sval
|
const svalue *null_ptr_sval
|
||||||
|
@ -7085,52 +7087,39 @@ region_model::unbind_region_and_descendents (const region *reg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implementation of BindingVisitor.
|
/* Find any pointers to REG or its descendents; convert them to
|
||||||
Update the bound svalues for regions below REG to use poisoned
|
poisoned values of kind PKIND. */
|
||||||
values instead. */
|
|
||||||
|
|
||||||
struct bad_pointer_finder
|
void
|
||||||
|
region_model::poison_any_pointers_to_descendents (const region *reg,
|
||||||
|
enum poison_kind pkind)
|
||||||
{
|
{
|
||||||
bad_pointer_finder (const region *reg, enum poison_kind pkind,
|
for (const auto &cluster_iter : m_store)
|
||||||
region_model_manager *mgr)
|
|
||||||
: m_reg (reg), m_pkind (pkind), m_mgr (mgr), m_count (0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void on_binding (const binding_key *, const svalue *&sval)
|
|
||||||
{
|
{
|
||||||
|
binding_cluster *cluster = cluster_iter.second;
|
||||||
|
for (auto iter = cluster->begin ();
|
||||||
|
iter != cluster->end ();
|
||||||
|
++iter)
|
||||||
|
{
|
||||||
|
auto bp = *iter;
|
||||||
|
const svalue *sval = bp.m_sval;
|
||||||
if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
|
if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
|
||||||
{
|
{
|
||||||
const region *ptr_dst = ptr_sval->get_pointee ();
|
const region *ptr_dst = ptr_sval->get_pointee ();
|
||||||
/* Poison ptrs to descendents of REG, but not to REG itself,
|
/* Poison ptrs to descendents of REG, but not to REG itself,
|
||||||
otherwise double-free detection doesn't work (since sm-state
|
otherwise double-free detection doesn't work (since sm-state
|
||||||
for "free" is stored on the original ptr svalue). */
|
for "free" is stored on the original ptr svalue). */
|
||||||
if (ptr_dst->descendent_of_p (m_reg)
|
if (ptr_dst->descendent_of_p (reg)
|
||||||
&& ptr_dst != m_reg)
|
&& ptr_dst != reg)
|
||||||
{
|
{
|
||||||
sval = m_mgr->get_or_create_poisoned_svalue (m_pkind,
|
const svalue *new_sval
|
||||||
|
= m_mgr->get_or_create_poisoned_svalue (pkind,
|
||||||
sval->get_type ());
|
sval->get_type ());
|
||||||
++m_count;
|
cluster->get_map ().overwrite (iter, new_sval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const region *m_reg;
|
|
||||||
enum poison_kind m_pkind;
|
|
||||||
region_model_manager *const m_mgr;
|
|
||||||
int m_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Find any pointers to REG or its descendents; convert them to
|
|
||||||
poisoned values of kind PKIND.
|
|
||||||
Return the number of pointers that were poisoned. */
|
|
||||||
|
|
||||||
int
|
|
||||||
region_model::poison_any_pointers_to_descendents (const region *reg,
|
|
||||||
enum poison_kind pkind)
|
|
||||||
{
|
|
||||||
bad_pointer_finder bv (reg, pkind, m_mgr);
|
|
||||||
m_store.for_each_binding (bv);
|
|
||||||
return bv.m_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to merge THIS with OTHER_MODEL, writing the result
|
/* Attempt to merge THIS with OTHER_MODEL, writing the result
|
||||||
|
@ -7647,12 +7636,12 @@ private:
|
||||||
/* Find keys for uninit svals. */
|
/* Find keys for uninit svals. */
|
||||||
for (auto iter : *compound_sval)
|
for (auto iter : *compound_sval)
|
||||||
{
|
{
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.m_sval;
|
||||||
if (const poisoned_svalue *psval
|
if (const poisoned_svalue *psval
|
||||||
= sval->dyn_cast_poisoned_svalue ())
|
= sval->dyn_cast_poisoned_svalue ())
|
||||||
if (psval->get_poison_kind () == poison_kind::uninit)
|
if (psval->get_poison_kind () == poison_kind::uninit)
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
const concrete_binding *ckey
|
const concrete_binding *ckey
|
||||||
= key->dyn_cast_concrete_binding ();
|
= key->dyn_cast_concrete_binding ();
|
||||||
gcc_assert (ckey);
|
gcc_assert (ckey);
|
||||||
|
@ -7699,12 +7688,12 @@ private:
|
||||||
auto_vec<const concrete_binding *> uninit_keys;
|
auto_vec<const concrete_binding *> uninit_keys;
|
||||||
for (auto iter : *compound_sval)
|
for (auto iter : *compound_sval)
|
||||||
{
|
{
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.m_sval;
|
||||||
if (const poisoned_svalue *psval
|
if (const poisoned_svalue *psval
|
||||||
= sval->dyn_cast_poisoned_svalue ())
|
= sval->dyn_cast_poisoned_svalue ())
|
||||||
if (psval->get_poison_kind () == poison_kind::uninit)
|
if (psval->get_poison_kind () == poison_kind::uninit)
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
const concrete_binding *ckey
|
const concrete_binding *ckey
|
||||||
= key->dyn_cast_concrete_binding ();
|
= key->dyn_cast_concrete_binding ();
|
||||||
gcc_assert (ckey);
|
gcc_assert (ckey);
|
||||||
|
@ -7914,7 +7903,7 @@ contains_uninit_p (const svalue *sval)
|
||||||
|
|
||||||
for (auto iter : *compound_sval)
|
for (auto iter : *compound_sval)
|
||||||
{
|
{
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.m_sval;
|
||||||
if (const poisoned_svalue *psval
|
if (const poisoned_svalue *psval
|
||||||
= sval->dyn_cast_poisoned_svalue ())
|
= sval->dyn_cast_poisoned_svalue ())
|
||||||
if (psval->get_poison_kind () == poison_kind::uninit)
|
if (psval->get_poison_kind () == poison_kind::uninit)
|
||||||
|
@ -8352,8 +8341,9 @@ test_struct ()
|
||||||
|
|
||||||
region_model_manager mgr;
|
region_model_manager mgr;
|
||||||
region_model model (&mgr);
|
region_model model (&mgr);
|
||||||
model.set_value (c_x, int_17, nullptr);
|
/* Set fields in order y, then x. */
|
||||||
model.set_value (c_y, int_m3, nullptr);
|
model.set_value (c_y, int_m3, nullptr);
|
||||||
|
model.set_value (c_x, int_17, nullptr);
|
||||||
|
|
||||||
/* Verify get_offset for "c.x". */
|
/* Verify get_offset for "c.x". */
|
||||||
{
|
{
|
||||||
|
@ -8370,6 +8360,27 @@ test_struct ()
|
||||||
ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr));
|
ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr));
|
||||||
ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE);
|
ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check iteration order of binding_cluster (and thus of binding_map). */
|
||||||
|
{
|
||||||
|
std::vector<binding_map::binding_pair> vec;
|
||||||
|
auto cluster
|
||||||
|
= model.get_store ()->get_cluster (model.get_lvalue (c, nullptr));
|
||||||
|
for (auto iter : *cluster)
|
||||||
|
vec.push_back (iter);
|
||||||
|
ASSERT_EQ (vec.size (), 2);
|
||||||
|
/* we should get them back in ascending order in memory (x then y). */
|
||||||
|
/* x */
|
||||||
|
ASSERT_EQ (vec[0].m_key->dyn_cast_concrete_binding ()->get_bit_range (),
|
||||||
|
bit_range (0, INT_TYPE_SIZE));
|
||||||
|
ASSERT_TRUE (tree_int_cst_equal(vec[0].m_sval->maybe_get_constant (),
|
||||||
|
int_17));
|
||||||
|
/* y */
|
||||||
|
ASSERT_EQ (vec[1].m_key->dyn_cast_concrete_binding ()->get_bit_range (),
|
||||||
|
bit_range (INT_TYPE_SIZE, INT_TYPE_SIZE));
|
||||||
|
ASSERT_TRUE (tree_int_cst_equal(vec[1].m_sval->maybe_get_constant (),
|
||||||
|
int_m3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify usage of an array element. */
|
/* Verify usage of an array element. */
|
||||||
|
|
|
@ -715,7 +715,7 @@ private:
|
||||||
region_model_context *ctxt,
|
region_model_context *ctxt,
|
||||||
std::unique_ptr<rejected_constraint> *out);
|
std::unique_ptr<rejected_constraint> *out);
|
||||||
|
|
||||||
int poison_any_pointers_to_descendents (const region *reg,
|
void poison_any_pointers_to_descendents (const region *reg,
|
||||||
enum poison_kind pkind);
|
enum poison_kind pkind);
|
||||||
|
|
||||||
void on_top_level_param (tree param,
|
void on_top_level_param (tree param,
|
||||||
|
|
|
@ -591,7 +591,7 @@ region::calc_initial_value_at_main (region_model_manager *mgr) const
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Get the value for REG within base_reg_init. */
|
/* Get the value for REG within base_reg_init. */
|
||||||
binding_cluster c (base_reg);
|
binding_cluster c (*mgr->get_store_manager (), base_reg);
|
||||||
c.bind (mgr->get_store_manager (), base_reg, base_reg_init);
|
c.bind (mgr->get_store_manager (), base_reg, base_reg_init);
|
||||||
const svalue *sval
|
const svalue *sval
|
||||||
= c.get_any_binding (mgr->get_store_manager (), this);
|
= c.get_any_binding (mgr->get_store_manager (), this);
|
||||||
|
@ -1713,7 +1713,7 @@ decl_region::calc_svalue_for_constructor (tree ctor,
|
||||||
/* Create a binding map, applying ctor to it, using this
|
/* Create a binding map, applying ctor to it, using this
|
||||||
decl_region as the base region when building child regions
|
decl_region as the base region when building child regions
|
||||||
for offset calculations. */
|
for offset calculations. */
|
||||||
binding_map map;
|
binding_map map (*mgr->get_store_manager ());
|
||||||
if (!map.apply_ctor_to_region (this, ctor, mgr))
|
if (!map.apply_ctor_to_region (this, ctor, mgr))
|
||||||
return mgr->get_or_create_unknown_svalue (get_type ());
|
return mgr->get_or_create_unknown_svalue (get_type ());
|
||||||
|
|
||||||
|
@ -1772,7 +1772,7 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const
|
||||||
if (!tracked_p ())
|
if (!tracked_p ())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
binding_cluster c (this);
|
binding_cluster c (*mgr->get_store_manager (), this);
|
||||||
c.zero_fill_region (mgr->get_store_manager (), this);
|
c.zero_fill_region (mgr->get_store_manager (), this);
|
||||||
return mgr->get_or_create_compound_svalue (TREE_TYPE (m_decl),
|
return mgr->get_or_create_compound_svalue (TREE_TYPE (m_decl),
|
||||||
c.get_map ());
|
c.get_map ());
|
||||||
|
|
|
@ -618,12 +618,103 @@ simplify_for_binding (const svalue *sval)
|
||||||
return sval;
|
return sval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* class binding_map::const_iterator. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
binding_map::const_iterator::operator== (const binding_map::const_iterator &other) const
|
||||||
|
{
|
||||||
|
if (m_concrete != other.m_concrete)
|
||||||
|
return false;
|
||||||
|
if (m_symbolic != other.m_symbolic)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::const_iterator &
|
||||||
|
binding_map::const_iterator::operator++ ()
|
||||||
|
{
|
||||||
|
if (m_concrete != m_map.m_concrete.end ())
|
||||||
|
++m_concrete;
|
||||||
|
else
|
||||||
|
++m_symbolic;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::binding_pair
|
||||||
|
binding_map::const_iterator::operator* ()
|
||||||
|
{
|
||||||
|
if (m_concrete != m_map.m_concrete.end ())
|
||||||
|
{
|
||||||
|
const bit_range &bits = m_concrete->first;
|
||||||
|
const svalue *sval = m_concrete->second;
|
||||||
|
return binding_pair (m_map.m_store_mgr.get_concrete_binding (bits), sval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gcc_assert (m_symbolic != m_map.m_symbolic.end ());
|
||||||
|
const region *reg = m_symbolic->m_region;
|
||||||
|
const svalue *sval = m_symbolic->m_sval;
|
||||||
|
return binding_pair (m_map.m_store_mgr.get_symbolic_binding (reg), sval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* class binding_map::iterator. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
binding_map::iterator::operator== (const binding_map::iterator &other) const
|
||||||
|
{
|
||||||
|
if (m_concrete != other.m_concrete)
|
||||||
|
return false;
|
||||||
|
if (m_symbolic != other.m_symbolic)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::iterator &
|
||||||
|
binding_map::iterator::operator++ ()
|
||||||
|
{
|
||||||
|
if (m_concrete != m_map.m_concrete.end ())
|
||||||
|
++m_concrete;
|
||||||
|
else
|
||||||
|
++m_symbolic;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::binding_pair
|
||||||
|
binding_map::iterator::operator* ()
|
||||||
|
{
|
||||||
|
if (m_concrete != m_map.m_concrete.end ())
|
||||||
|
{
|
||||||
|
const bit_range &bits = m_concrete->first;
|
||||||
|
const svalue *&sval = m_concrete->second;
|
||||||
|
return binding_pair (m_map.m_store_mgr.get_concrete_binding (bits), sval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gcc_assert (m_symbolic != m_map.m_symbolic.end ());
|
||||||
|
const region *reg = m_symbolic->m_region;
|
||||||
|
const svalue *&sval = m_symbolic->m_sval;
|
||||||
|
return binding_pair (m_map.m_store_mgr.get_symbolic_binding (reg), sval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* class binding_map. */
|
/* class binding_map. */
|
||||||
|
|
||||||
|
// Construct an empty binding_map.
|
||||||
|
|
||||||
|
binding_map::binding_map (store_manager &store_mgr)
|
||||||
|
: m_store_mgr (store_mgr),
|
||||||
|
m_concrete (),
|
||||||
|
m_symbolic ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* binding_map's copy ctor. */
|
/* binding_map's copy ctor. */
|
||||||
|
|
||||||
binding_map::binding_map (const binding_map &other)
|
binding_map::binding_map (const binding_map &other)
|
||||||
: m_map (other.m_map)
|
: m_store_mgr (other.m_store_mgr),
|
||||||
|
m_concrete (other.m_concrete),
|
||||||
|
m_symbolic (other.m_symbolic)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,15 +723,15 @@ binding_map::binding_map (const binding_map &other)
|
||||||
binding_map&
|
binding_map&
|
||||||
binding_map::operator= (const binding_map &other)
|
binding_map::operator= (const binding_map &other)
|
||||||
{
|
{
|
||||||
|
gcc_assert (&m_store_mgr == &other.m_store_mgr);
|
||||||
|
|
||||||
/* For now, assume we only ever copy to an empty cluster. */
|
/* For now, assume we only ever copy to an empty cluster. */
|
||||||
gcc_assert (m_map.elements () == 0);
|
gcc_assert (m_concrete.size () == 0);
|
||||||
for (map_t::iterator iter = other.m_map.begin (); iter != other.m_map.end ();
|
gcc_assert (m_symbolic.size () == 0);
|
||||||
++iter)
|
|
||||||
{
|
m_concrete = other.m_concrete;
|
||||||
const binding_key *key = (*iter).first;
|
m_symbolic = other.m_symbolic;
|
||||||
const svalue *sval = (*iter).second;
|
|
||||||
m_map.put (key, sval);
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,21 +740,11 @@ binding_map::operator=(const binding_map &other)
|
||||||
bool
|
bool
|
||||||
binding_map::operator== (const binding_map &other) const
|
binding_map::operator== (const binding_map &other) const
|
||||||
{
|
{
|
||||||
if (m_map.elements () != other.m_map.elements ())
|
if (m_concrete != other.m_concrete)
|
||||||
|
return false;
|
||||||
|
if (m_symbolic != other.m_symbolic)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
|
||||||
{
|
|
||||||
const binding_key *key = (*iter).first;
|
|
||||||
const svalue *sval = (*iter).second;
|
|
||||||
const svalue **other_slot
|
|
||||||
= const_cast <map_t &> (other.m_map).get (key);
|
|
||||||
if (other_slot == nullptr)
|
|
||||||
return false;
|
|
||||||
if (sval != *other_slot)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
gcc_checking_assert (hash () == other.hash ());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,18 +754,140 @@ hashval_t
|
||||||
binding_map::hash () const
|
binding_map::hash () const
|
||||||
{
|
{
|
||||||
hashval_t result = 0;
|
hashval_t result = 0;
|
||||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
for (auto iter : *this)
|
||||||
{
|
{
|
||||||
/* Use a new hasher for each key to avoid depending on the ordering
|
/* Use a new hasher for each key to avoid depending on the ordering
|
||||||
of keys when accumulating the result. */
|
of keys when accumulating the result. */
|
||||||
inchash::hash hstate;
|
inchash::hash hstate;
|
||||||
hstate.add_ptr ((*iter).first);
|
hstate.add_ptr (iter.m_key);
|
||||||
hstate.add_ptr ((*iter).second);
|
hstate.add_ptr (iter.m_sval);
|
||||||
result ^= hstate.end ();
|
result ^= hstate.end ();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const svalue *
|
||||||
|
binding_map::get (const binding_key *key) const
|
||||||
|
{
|
||||||
|
if (key->symbolic_p ())
|
||||||
|
{
|
||||||
|
const ana::symbolic_binding &sym_key
|
||||||
|
= *static_cast <const ana::symbolic_binding *> (key);
|
||||||
|
const region *reg = sym_key.get_region ();
|
||||||
|
|
||||||
|
for (auto iter : m_symbolic)
|
||||||
|
{
|
||||||
|
if (iter.m_region == reg)
|
||||||
|
return iter.m_sval;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const concrete_binding &conc_key
|
||||||
|
= *static_cast <const concrete_binding *> (key);
|
||||||
|
const bit_range &bits = conc_key.get_bit_range ();
|
||||||
|
|
||||||
|
concrete_bindings_t::const_iterator iter (m_concrete.find (bits));
|
||||||
|
if (iter != m_concrete.end ())
|
||||||
|
return iter->second;
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
binding_map::put (const binding_key *key, const svalue *sval)
|
||||||
|
{
|
||||||
|
if (key->symbolic_p ())
|
||||||
|
{
|
||||||
|
const ana::symbolic_binding &sym_key
|
||||||
|
= *static_cast <const ana::symbolic_binding *> (key);
|
||||||
|
const region *reg = sym_key.get_region ();
|
||||||
|
|
||||||
|
m_symbolic.clear ();
|
||||||
|
|
||||||
|
m_symbolic.push_back ({reg, sval});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const concrete_binding &conc_key
|
||||||
|
= *static_cast <const concrete_binding *> (key);
|
||||||
|
const bit_range &bits = conc_key.get_bit_range ();
|
||||||
|
|
||||||
|
concrete_bindings_t::iterator iter (m_concrete.find (bits));
|
||||||
|
if (iter != m_concrete.end ())
|
||||||
|
(*iter).second = sval;
|
||||||
|
else
|
||||||
|
m_concrete.insert ({bits, sval});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
binding_map::overwrite (iterator_t &pos, const svalue *v)
|
||||||
|
{
|
||||||
|
gcc_assert (&pos.m_map == this);
|
||||||
|
if (pos.m_symbolic != m_symbolic.end ())
|
||||||
|
(*(pos.m_symbolic)).m_sval = v;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gcc_assert (pos.m_concrete != m_concrete.end ());
|
||||||
|
(*(pos.m_concrete)).second = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
binding_map::remove (const binding_key *key)
|
||||||
|
{
|
||||||
|
if (key->symbolic_p ())
|
||||||
|
m_symbolic.clear ();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const concrete_binding &conc_key
|
||||||
|
= *static_cast <const concrete_binding *> (key);
|
||||||
|
const bit_range &bits = conc_key.get_bit_range ();
|
||||||
|
m_concrete.erase (bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::const_iterator_t
|
||||||
|
binding_map::begin () const
|
||||||
|
{
|
||||||
|
return binding_map::const_iterator_t (*this,
|
||||||
|
m_concrete.begin (),
|
||||||
|
m_symbolic.begin ());
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::const_iterator_t
|
||||||
|
binding_map::end () const
|
||||||
|
{
|
||||||
|
return binding_map::const_iterator_t (*this,
|
||||||
|
m_concrete.end (),
|
||||||
|
m_symbolic.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::iterator_t
|
||||||
|
binding_map::begin ()
|
||||||
|
{
|
||||||
|
return binding_map::iterator_t (*this,
|
||||||
|
m_concrete.begin (),
|
||||||
|
m_symbolic.begin ());
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_map::iterator_t
|
||||||
|
binding_map::end ()
|
||||||
|
{
|
||||||
|
return binding_map::iterator_t (*this,
|
||||||
|
m_concrete.end (),
|
||||||
|
m_symbolic.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
binding_map::elements () const
|
||||||
|
{
|
||||||
|
return m_concrete.size () + m_symbolic.size ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Dump a representation of this binding_map to PP.
|
/* Dump a representation of this binding_map to PP.
|
||||||
SIMPLE controls how values and regions are to be printed.
|
SIMPLE controls how values and regions are to be printed.
|
||||||
If MULTILINE, then split the dump over multiple lines and
|
If MULTILINE, then split the dump over multiple lines and
|
||||||
|
@ -694,20 +897,11 @@ void
|
||||||
binding_map::dump_to_pp (pretty_printer *pp, bool simple,
|
binding_map::dump_to_pp (pretty_printer *pp, bool simple,
|
||||||
bool multiline) const
|
bool multiline) const
|
||||||
{
|
{
|
||||||
auto_vec <const binding_key *> binding_keys;
|
bool first = true;
|
||||||
for (map_t::iterator iter = m_map.begin ();
|
for (auto iter : *this)
|
||||||
iter != m_map.end (); ++iter)
|
|
||||||
{
|
{
|
||||||
const binding_key *key = (*iter).first;
|
const binding_key *key = iter.m_key;
|
||||||
binding_keys.safe_push (key);
|
const svalue *value = iter.m_sval;
|
||||||
}
|
|
||||||
binding_keys.qsort (binding_key::cmp_ptrs);
|
|
||||||
|
|
||||||
const binding_key *key;
|
|
||||||
unsigned i;
|
|
||||||
FOR_EACH_VEC_ELT (binding_keys, i, key)
|
|
||||||
{
|
|
||||||
const svalue *value = *const_cast <map_t &> (m_map).get (key);
|
|
||||||
if (multiline)
|
if (multiline)
|
||||||
{
|
{
|
||||||
pp_string (pp, " key: {");
|
pp_string (pp, " key: {");
|
||||||
|
@ -724,7 +918,9 @@ binding_map::dump_to_pp (pretty_printer *pp, bool simple,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
pp_string (pp, ", ");
|
pp_string (pp, ", ");
|
||||||
pp_string (pp, "binding key: {");
|
pp_string (pp, "binding key: {");
|
||||||
key->dump_to_pp (pp, simple);
|
key->dump_to_pp (pp, simple);
|
||||||
|
@ -754,21 +950,10 @@ binding_map::to_json () const
|
||||||
{
|
{
|
||||||
auto map_obj = std::make_unique<json::object> ();
|
auto map_obj = std::make_unique<json::object> ();
|
||||||
|
|
||||||
auto_vec <const binding_key *> binding_keys;
|
for (auto iter : *this)
|
||||||
for (map_t::iterator iter = m_map.begin ();
|
|
||||||
iter != m_map.end (); ++iter)
|
|
||||||
{
|
{
|
||||||
const binding_key *key = (*iter).first;
|
const svalue *value = iter.m_sval;
|
||||||
binding_keys.safe_push (key);
|
label_text key_desc = iter.m_key->get_desc ();
|
||||||
}
|
|
||||||
binding_keys.qsort (binding_key::cmp_ptrs);
|
|
||||||
|
|
||||||
const binding_key *key;
|
|
||||||
unsigned i;
|
|
||||||
FOR_EACH_VEC_ELT (binding_keys, i, key)
|
|
||||||
{
|
|
||||||
const svalue *value = *const_cast <map_t &> (m_map).get (key);
|
|
||||||
label_text key_desc = key->get_desc ();
|
|
||||||
map_obj->set (key_desc.get (), value->to_json ());
|
map_obj->set (key_desc.get (), value->to_json ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -805,20 +990,10 @@ void
|
||||||
binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,
|
binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,
|
||||||
const text_art::dump_widget_info &dwi) const
|
const text_art::dump_widget_info &dwi) const
|
||||||
{
|
{
|
||||||
auto_vec <const binding_key *> binding_keys;
|
for (auto iter : *this)
|
||||||
for (map_t::iterator iter = m_map.begin ();
|
|
||||||
iter != m_map.end (); ++iter)
|
|
||||||
{
|
{
|
||||||
const binding_key *key = (*iter).first;
|
const binding_key *key = iter.m_key;
|
||||||
binding_keys.safe_push (key);
|
const svalue *sval = iter.m_sval;
|
||||||
}
|
|
||||||
binding_keys.qsort (binding_key::cmp_ptrs);
|
|
||||||
|
|
||||||
const binding_key *key;
|
|
||||||
unsigned i;
|
|
||||||
FOR_EACH_VEC_ELT (binding_keys, i, key)
|
|
||||||
{
|
|
||||||
const svalue *sval = *const_cast <map_t &> (m_map).get (key);
|
|
||||||
add_binding_to_tree_widget (parent_widget, dwi,
|
add_binding_to_tree_widget (parent_widget, dwi,
|
||||||
key, sval);
|
key, sval);
|
||||||
}
|
}
|
||||||
|
@ -834,15 +1009,13 @@ binding_map::cmp (const binding_map &map1, const binding_map &map2)
|
||||||
return count_cmp;
|
return count_cmp;
|
||||||
|
|
||||||
auto_vec <const binding_key *> keys1 (map1.elements ());
|
auto_vec <const binding_key *> keys1 (map1.elements ());
|
||||||
for (map_t::iterator iter = map1.begin ();
|
for (auto iter : map1)
|
||||||
iter != map1.end (); ++iter)
|
keys1.quick_push (iter.m_key);
|
||||||
keys1.quick_push ((*iter).first);
|
|
||||||
keys1.qsort (binding_key::cmp_ptrs);
|
keys1.qsort (binding_key::cmp_ptrs);
|
||||||
|
|
||||||
auto_vec <const binding_key *> keys2 (map2.elements ());
|
auto_vec <const binding_key *> keys2 (map2.elements ());
|
||||||
for (map_t::iterator iter = map2.begin ();
|
for (auto iter : map2)
|
||||||
iter != map2.end (); ++iter)
|
keys2.quick_push (iter.m_key);
|
||||||
keys2.quick_push ((*iter).first);
|
|
||||||
keys2.qsort (binding_key::cmp_ptrs);
|
keys2.qsort (binding_key::cmp_ptrs);
|
||||||
|
|
||||||
for (size_t i = 0; i < keys1.length (); i++)
|
for (size_t i = 0; i < keys1.length (); i++)
|
||||||
|
@ -1096,7 +1269,7 @@ binding_map::get_overlapping_bindings (const binding_key *key,
|
||||||
{
|
{
|
||||||
for (auto iter : *this)
|
for (auto iter : *this)
|
||||||
{
|
{
|
||||||
const binding_key *iter_key = iter.first;
|
const binding_key *iter_key = iter.m_key;
|
||||||
if (const concrete_binding *ckey
|
if (const concrete_binding *ckey
|
||||||
= key->dyn_cast_concrete_binding ())
|
= key->dyn_cast_concrete_binding ())
|
||||||
{
|
{
|
||||||
|
@ -1200,7 +1373,7 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,
|
||||||
auto_vec<const binding_key *> bindings;
|
auto_vec<const binding_key *> bindings;
|
||||||
if (always_overlap)
|
if (always_overlap)
|
||||||
for (auto iter : *this)
|
for (auto iter : *this)
|
||||||
bindings.safe_push (iter.first); /* Add all bindings. */
|
bindings.safe_push (iter.m_key); /* Add all bindings. */
|
||||||
else
|
else
|
||||||
/* Just add overlapping bindings. */
|
/* Just add overlapping bindings. */
|
||||||
get_overlapping_bindings (drop_key, &bindings);
|
get_overlapping_bindings (drop_key, &bindings);
|
||||||
|
@ -1234,7 +1407,7 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,
|
||||||
maybe_live_values->add (old_sval);
|
maybe_live_values->add (old_sval);
|
||||||
|
|
||||||
/* Begin by removing the old binding. */
|
/* Begin by removing the old binding. */
|
||||||
m_map.remove (iter_binding);
|
remove (iter_binding);
|
||||||
|
|
||||||
/* Don't attempt to handle prefixes/suffixes for the
|
/* Don't attempt to handle prefixes/suffixes for the
|
||||||
"always_overlap" case; everything's being removed. */
|
"always_overlap" case; everything's being removed. */
|
||||||
|
@ -1266,7 +1439,7 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,
|
||||||
= old_sval->extract_bit_range (NULL_TREE,
|
= old_sval->extract_bit_range (NULL_TREE,
|
||||||
rel_prefix,
|
rel_prefix,
|
||||||
mgr->get_svalue_manager ());
|
mgr->get_svalue_manager ());
|
||||||
m_map.put (prefix_key, prefix_sval);
|
put (prefix_key, prefix_sval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iter_bits.get_next_bit_offset ()
|
if (iter_bits.get_next_bit_offset ()
|
||||||
|
@ -1285,7 +1458,7 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,
|
||||||
= old_sval->extract_bit_range (NULL_TREE,
|
= old_sval->extract_bit_range (NULL_TREE,
|
||||||
rel_suffix,
|
rel_suffix,
|
||||||
mgr->get_svalue_manager ());
|
mgr->get_svalue_manager ());
|
||||||
m_map.put (suffix_key, suffix_sval);
|
put (suffix_key, suffix_sval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1293,8 +1466,9 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,
|
||||||
|
|
||||||
/* class binding_cluster. */
|
/* class binding_cluster. */
|
||||||
|
|
||||||
binding_cluster::binding_cluster (const region *base_region)
|
binding_cluster::binding_cluster (store_manager &store_mgr,
|
||||||
: m_base_region (base_region), m_map (),
|
const region *base_region)
|
||||||
|
: m_base_region (base_region), m_map (store_mgr),
|
||||||
m_escaped (false), m_touched (false)
|
m_escaped (false), m_touched (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1414,7 +1588,7 @@ binding_cluster::validate () const
|
||||||
int num_concrete = 0;
|
int num_concrete = 0;
|
||||||
for (auto iter : m_map)
|
for (auto iter : m_map)
|
||||||
{
|
{
|
||||||
if (iter.first->symbolic_p ())
|
if (iter.m_key->symbolic_p ())
|
||||||
num_symbolic++;
|
num_symbolic++;
|
||||||
else
|
else
|
||||||
num_concrete++;
|
num_concrete++;
|
||||||
|
@ -1537,11 +1711,10 @@ binding_cluster::bind_compound_sval (store_manager *mgr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (map_t::iterator iter = compound_sval->begin ();
|
for (auto iter : *compound_sval)
|
||||||
iter != compound_sval->end (); ++iter)
|
|
||||||
{
|
{
|
||||||
const binding_key *iter_key = (*iter).first;
|
const binding_key *iter_key = iter.m_key;
|
||||||
const svalue *iter_sval = (*iter).second;
|
const svalue *iter_sval = iter.m_sval;
|
||||||
|
|
||||||
if (const concrete_binding *concrete_key
|
if (const concrete_binding *concrete_key
|
||||||
= iter_key->dyn_cast_concrete_binding ())
|
= iter_key->dyn_cast_concrete_binding ())
|
||||||
|
@ -1650,7 +1823,7 @@ binding_cluster::purge_state_involving (const svalue *sval,
|
||||||
auto_vec<std::pair<const binding_key *, tree> > to_make_unknown;
|
auto_vec<std::pair<const binding_key *, tree> > to_make_unknown;
|
||||||
for (auto iter : m_map)
|
for (auto iter : m_map)
|
||||||
{
|
{
|
||||||
const binding_key *iter_key = iter.first;
|
const binding_key *iter_key = iter.m_key;
|
||||||
if (const symbolic_binding *symbolic_key
|
if (const symbolic_binding *symbolic_key
|
||||||
= iter_key->dyn_cast_symbolic_binding ())
|
= iter_key->dyn_cast_symbolic_binding ())
|
||||||
{
|
{
|
||||||
|
@ -1658,7 +1831,7 @@ binding_cluster::purge_state_involving (const svalue *sval,
|
||||||
if (reg->involves_p (sval))
|
if (reg->involves_p (sval))
|
||||||
to_remove.safe_push (iter_key);
|
to_remove.safe_push (iter_key);
|
||||||
}
|
}
|
||||||
const svalue *iter_sval = iter.second;
|
const svalue *iter_sval = iter.m_sval;
|
||||||
if (iter_sval->involves_p (sval))
|
if (iter_sval->involves_p (sval))
|
||||||
to_make_unknown.safe_push (std::make_pair(iter_key,
|
to_make_unknown.safe_push (std::make_pair(iter_key,
|
||||||
iter_sval->get_type ()));
|
iter_sval->get_type ()));
|
||||||
|
@ -1847,8 +2020,8 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
|
||||||
perhaps we should have a spatial-organized data structure for
|
perhaps we should have a spatial-organized data structure for
|
||||||
concrete keys, though. */
|
concrete keys, though. */
|
||||||
|
|
||||||
binding_map result_map;
|
binding_map result_map (*mgr);
|
||||||
binding_map default_map;
|
binding_map default_map (*mgr);
|
||||||
|
|
||||||
/* Set up default values in default_map. */
|
/* Set up default values in default_map. */
|
||||||
const svalue *default_sval;
|
const svalue *default_sval;
|
||||||
|
@ -1866,12 +2039,13 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
const concrete_binding *default_key_relative_to_reg
|
const concrete_binding *default_key_relative_to_reg
|
||||||
= mgr->get_concrete_binding (0, concrete_default_key->get_size_in_bits ());
|
= mgr->get_concrete_binding (0, concrete_default_key->get_size_in_bits ());
|
||||||
|
|
||||||
default_map.put (default_key_relative_to_reg, default_sval);
|
default_map.put (default_key_relative_to_reg, default_sval);
|
||||||
|
|
||||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
for (auto iter : m_map)
|
||||||
{
|
{
|
||||||
const binding_key *key = (*iter).first;
|
const binding_key *key = iter.m_key;
|
||||||
const svalue *sval = (*iter).second;
|
const svalue *sval = iter.m_sval;
|
||||||
|
|
||||||
if (const concrete_binding *concrete_key
|
if (const concrete_binding *concrete_key
|
||||||
= key->dyn_cast_concrete_binding ())
|
= key->dyn_cast_concrete_binding ())
|
||||||
|
@ -1957,8 +2131,8 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
|
||||||
/* Merge any bindings from default_map into result_map. */
|
/* Merge any bindings from default_map into result_map. */
|
||||||
for (auto iter : default_map)
|
for (auto iter : default_map)
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.m_sval;
|
||||||
result_map.put (key, sval);
|
result_map.put (key, sval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2051,16 +2225,14 @@ binding_cluster::can_merge_p (const binding_cluster *cluster_a,
|
||||||
gcc_assert (cluster_b->m_base_region == out_cluster->m_base_region);
|
gcc_assert (cluster_b->m_base_region == out_cluster->m_base_region);
|
||||||
|
|
||||||
hash_set<const binding_key *> keys;
|
hash_set<const binding_key *> keys;
|
||||||
for (map_t::iterator iter_a = cluster_a->m_map.begin ();
|
for (auto iter_a : cluster_a->m_map)
|
||||||
iter_a != cluster_a->m_map.end (); ++iter_a)
|
|
||||||
{
|
{
|
||||||
const binding_key *key_a = (*iter_a).first;
|
const binding_key *key_a = iter_a.m_key;
|
||||||
keys.add (key_a);
|
keys.add (key_a);
|
||||||
}
|
}
|
||||||
for (map_t::iterator iter_b = cluster_b->m_map.begin ();
|
for (auto iter_b : cluster_b->m_map)
|
||||||
iter_b != cluster_b->m_map.end (); ++iter_b)
|
|
||||||
{
|
{
|
||||||
const binding_key *key_b = (*iter_b).first;
|
const binding_key *key_b = iter_b.m_key;
|
||||||
keys.add (key_b);
|
keys.add (key_b);
|
||||||
}
|
}
|
||||||
int num_symbolic_keys = 0;
|
int num_symbolic_keys = 0;
|
||||||
|
@ -2122,7 +2294,7 @@ binding_cluster::can_merge_p (const binding_cluster *cluster_a,
|
||||||
|| (num_concrete_keys > 0 && num_symbolic_keys > 0))
|
|| (num_concrete_keys > 0 && num_symbolic_keys > 0))
|
||||||
{
|
{
|
||||||
out_cluster->m_touched = true;
|
out_cluster->m_touched = true;
|
||||||
out_cluster->m_map.empty ();
|
out_cluster->m_map.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't handle other kinds of overlaps yet. */
|
/* We don't handle other kinds of overlaps yet. */
|
||||||
|
@ -2141,11 +2313,10 @@ binding_cluster::make_unknown_relative_to (const binding_cluster *other,
|
||||||
store *out_store,
|
store *out_store,
|
||||||
store_manager *mgr)
|
store_manager *mgr)
|
||||||
{
|
{
|
||||||
for (map_t::iterator iter = other->m_map.begin ();
|
for (auto iter : *other)
|
||||||
iter != other->m_map.end (); ++iter)
|
|
||||||
{
|
{
|
||||||
const binding_key *iter_key = (*iter).first;
|
const binding_key *iter_key = iter.m_key;
|
||||||
const svalue *iter_sval = (*iter).second;
|
const svalue *iter_sval = iter.m_sval;
|
||||||
const svalue *unknown_sval
|
const svalue *unknown_sval
|
||||||
= mgr->get_svalue_manager ()->get_or_create_unknown_svalue
|
= mgr->get_svalue_manager ()->get_or_create_unknown_svalue
|
||||||
(iter_sval->get_type ());
|
(iter_sval->get_type ());
|
||||||
|
@ -2165,7 +2336,8 @@ binding_cluster::make_unknown_relative_to (const binding_cluster *other,
|
||||||
if (base_reg->tracked_p ()
|
if (base_reg->tracked_p ()
|
||||||
&& !base_reg->symbolic_for_unknown_ptr_p ())
|
&& !base_reg->symbolic_for_unknown_ptr_p ())
|
||||||
{
|
{
|
||||||
binding_cluster *c = out_store->get_or_create_cluster (base_reg);
|
binding_cluster *c
|
||||||
|
= out_store->get_or_create_cluster (*mgr, base_reg);
|
||||||
c->mark_as_escaped ();
|
c->mark_as_escaped ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2193,7 +2365,7 @@ binding_cluster::on_unknown_fncall (const gcall &call,
|
||||||
{
|
{
|
||||||
if (m_escaped)
|
if (m_escaped)
|
||||||
{
|
{
|
||||||
m_map.empty ();
|
m_map.clear ();
|
||||||
|
|
||||||
if (!m_base_region->empty_p ())
|
if (!m_base_region->empty_p ())
|
||||||
{
|
{
|
||||||
|
@ -2216,7 +2388,7 @@ binding_cluster::on_asm (const gasm *stmt,
|
||||||
store_manager *mgr,
|
store_manager *mgr,
|
||||||
const conjured_purge &p)
|
const conjured_purge &p)
|
||||||
{
|
{
|
||||||
m_map.empty ();
|
m_map.clear ();
|
||||||
|
|
||||||
/* Bind it to a new "conjured" value using CALL. */
|
/* Bind it to a new "conjured" value using CALL. */
|
||||||
const svalue *sval
|
const svalue *sval
|
||||||
|
@ -2279,10 +2451,10 @@ binding_cluster::get_representative_path_vars (const region_model *model,
|
||||||
{
|
{
|
||||||
sval = simplify_for_binding (sval);
|
sval = simplify_for_binding (sval);
|
||||||
|
|
||||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
for (auto iter : m_map)
|
||||||
{
|
{
|
||||||
const binding_key *key = (*iter).first;
|
const binding_key *key = iter.m_key;
|
||||||
const svalue *bound_sval = (*iter).second;
|
const svalue *bound_sval = iter.m_sval;
|
||||||
if (bound_sval == sval)
|
if (bound_sval == sval)
|
||||||
{
|
{
|
||||||
if (const concrete_binding *ckey
|
if (const concrete_binding *ckey
|
||||||
|
@ -2804,14 +2976,14 @@ store::set_value (store_manager *mgr, const region *lhs_reg,
|
||||||
{
|
{
|
||||||
const region *ptr_dst = ptr_sval->get_pointee ();
|
const region *ptr_dst = ptr_sval->get_pointee ();
|
||||||
const region *ptr_base_reg = ptr_dst->get_base_region ();
|
const region *ptr_base_reg = ptr_dst->get_base_region ();
|
||||||
mark_as_escaped (ptr_base_reg);
|
mark_as_escaped (*mgr, ptr_base_reg);
|
||||||
}
|
}
|
||||||
if (uncertainty)
|
if (uncertainty)
|
||||||
uncertainty->on_maybe_bound_sval (rhs_sval);
|
uncertainty->on_maybe_bound_sval (rhs_sval);
|
||||||
}
|
}
|
||||||
else if (lhs_base_reg->tracked_p ())
|
else if (lhs_base_reg->tracked_p ())
|
||||||
{
|
{
|
||||||
lhs_cluster = get_or_create_cluster (lhs_base_reg);
|
lhs_cluster = get_or_create_cluster (*mgr, lhs_base_reg);
|
||||||
lhs_cluster->bind (mgr, lhs_reg, rhs_sval);
|
lhs_cluster->bind (mgr, lhs_reg, rhs_sval);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2887,7 +3059,7 @@ store::set_value (store_manager *mgr, const region *lhs_reg,
|
||||||
(e.g. marking regions as escaped).
|
(e.g. marking regions as escaped).
|
||||||
We do this after the iteration to avoid potentially changing
|
We do this after the iteration to avoid potentially changing
|
||||||
m_cluster_map whilst iterating over it. */
|
m_cluster_map whilst iterating over it. */
|
||||||
on_maybe_live_values (maybe_live_values);
|
on_maybe_live_values (*mgr, maybe_live_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine if BASE_REG_A could be an alias of BASE_REG_B. */
|
/* Determine if BASE_REG_A could be an alias of BASE_REG_B. */
|
||||||
|
@ -2983,14 +3155,15 @@ store::eval_alias_1 (const region *base_reg_a,
|
||||||
/* Record all of the values in MAYBE_LIVE_VALUES as being possibly live. */
|
/* Record all of the values in MAYBE_LIVE_VALUES as being possibly live. */
|
||||||
|
|
||||||
void
|
void
|
||||||
store::on_maybe_live_values (const svalue_set &maybe_live_values)
|
store::on_maybe_live_values (store_manager &mgr,
|
||||||
|
const svalue_set &maybe_live_values)
|
||||||
{
|
{
|
||||||
for (auto sval : maybe_live_values)
|
for (auto sval : maybe_live_values)
|
||||||
{
|
{
|
||||||
if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
|
if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
|
||||||
{
|
{
|
||||||
const region *base_reg = ptr_sval->get_pointee ()->get_base_region ();
|
const region *base_reg = ptr_sval->get_pointee ()->get_base_region ();
|
||||||
mark_as_escaped (base_reg);
|
mark_as_escaped (mgr, base_reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3044,7 +3217,7 @@ store::fill_region (store_manager *mgr, const region *reg, const svalue *sval)
|
||||||
if (base_reg->symbolic_for_unknown_ptr_p ()
|
if (base_reg->symbolic_for_unknown_ptr_p ()
|
||||||
|| !base_reg->tracked_p ())
|
|| !base_reg->tracked_p ())
|
||||||
return;
|
return;
|
||||||
binding_cluster *cluster = get_or_create_cluster (base_reg);
|
binding_cluster *cluster = get_or_create_cluster (*mgr, base_reg);
|
||||||
cluster->fill_region (mgr, reg, sval);
|
cluster->fill_region (mgr, reg, sval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3069,7 +3242,7 @@ store::mark_region_as_unknown (store_manager *mgr, const region *reg,
|
||||||
if (base_reg->symbolic_for_unknown_ptr_p ()
|
if (base_reg->symbolic_for_unknown_ptr_p ()
|
||||||
|| !base_reg->tracked_p ())
|
|| !base_reg->tracked_p ())
|
||||||
return;
|
return;
|
||||||
binding_cluster *cluster = get_or_create_cluster (base_reg);
|
binding_cluster *cluster = get_or_create_cluster (*mgr, base_reg);
|
||||||
cluster->mark_region_as_unknown (mgr, reg, reg, uncertainty,
|
cluster->mark_region_as_unknown (mgr, reg, reg, uncertainty,
|
||||||
maybe_live_values);
|
maybe_live_values);
|
||||||
}
|
}
|
||||||
|
@ -3127,7 +3300,8 @@ store::get_cluster (const region *base_reg)
|
||||||
/* Get the cluster for BASE_REG, creating it if doesn't already exist. */
|
/* Get the cluster for BASE_REG, creating it if doesn't already exist. */
|
||||||
|
|
||||||
binding_cluster *
|
binding_cluster *
|
||||||
store::get_or_create_cluster (const region *base_reg)
|
store::get_or_create_cluster (store_manager &store_mgr,
|
||||||
|
const region *base_reg)
|
||||||
{
|
{
|
||||||
gcc_assert (base_reg);
|
gcc_assert (base_reg);
|
||||||
gcc_assert (base_reg->get_base_region () == base_reg);
|
gcc_assert (base_reg->get_base_region () == base_reg);
|
||||||
|
@ -3141,7 +3315,7 @@ store::get_or_create_cluster (const region *base_reg)
|
||||||
if (binding_cluster **slot = m_cluster_map.get (base_reg))
|
if (binding_cluster **slot = m_cluster_map.get (base_reg))
|
||||||
return *slot;
|
return *slot;
|
||||||
|
|
||||||
binding_cluster *cluster = new binding_cluster (base_reg);
|
binding_cluster *cluster = new binding_cluster (store_mgr, base_reg);
|
||||||
m_cluster_map.put (base_reg, cluster);
|
m_cluster_map.put (base_reg, cluster);
|
||||||
|
|
||||||
return cluster;
|
return cluster;
|
||||||
|
@ -3206,7 +3380,7 @@ store::can_merge_p (const store *store_a, const store *store_b,
|
||||||
const binding_cluster *cluster_b = store_b->get_cluster (base_reg);
|
const binding_cluster *cluster_b = store_b->get_cluster (base_reg);
|
||||||
/* At least one of cluster_a and cluster_b must be non-NULL. */
|
/* At least one of cluster_a and cluster_b must be non-NULL. */
|
||||||
binding_cluster *out_cluster
|
binding_cluster *out_cluster
|
||||||
= out_store->get_or_create_cluster (base_reg);
|
= out_store->get_or_create_cluster (*mgr, base_reg);
|
||||||
if (!binding_cluster::can_merge_p (cluster_a, cluster_b,
|
if (!binding_cluster::can_merge_p (cluster_a, cluster_b,
|
||||||
out_cluster, out_store, mgr, merger))
|
out_cluster, out_store, mgr, merger))
|
||||||
return false;
|
return false;
|
||||||
|
@ -3221,7 +3395,7 @@ store::can_merge_p (const store *store_a, const store *store_b,
|
||||||
isn't reachable from args of those calls. */
|
isn't reachable from args of those calls. */
|
||||||
|
|
||||||
void
|
void
|
||||||
store::mark_as_escaped (const region *base_reg)
|
store::mark_as_escaped (store_manager &mgr, const region *base_reg)
|
||||||
{
|
{
|
||||||
gcc_assert (base_reg);
|
gcc_assert (base_reg);
|
||||||
gcc_assert (base_reg->get_base_region () == base_reg);
|
gcc_assert (base_reg->get_base_region () == base_reg);
|
||||||
|
@ -3230,7 +3404,7 @@ store::mark_as_escaped (const region *base_reg)
|
||||||
|| !base_reg->tracked_p ())
|
|| !base_reg->tracked_p ())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
binding_cluster *cluster = get_or_create_cluster (base_reg);
|
binding_cluster *cluster = get_or_create_cluster (mgr, base_reg);
|
||||||
cluster->mark_as_escaped ();
|
cluster->mark_as_escaped ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3361,7 +3535,7 @@ store::canonicalize (store_manager *mgr)
|
||||||
binding_cluster *cluster = (*iter).second;
|
binding_cluster *cluster = (*iter).second;
|
||||||
for (binding_cluster::iterator_t bind_iter = cluster->m_map.begin ();
|
for (binding_cluster::iterator_t bind_iter = cluster->m_map.begin ();
|
||||||
bind_iter != cluster->m_map.end (); ++bind_iter)
|
bind_iter != cluster->m_map.end (); ++bind_iter)
|
||||||
(*bind_iter).second->accept (&s);
|
(*bind_iter).m_sval->accept (&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Locate heap-allocated regions that have empty bindings that weren't
|
/* Locate heap-allocated regions that have empty bindings that weren't
|
||||||
|
@ -3442,12 +3616,13 @@ store::loop_replay_fixup (const store *other_store,
|
||||||
for (binding_cluster::iterator_t bind_iter = cluster->m_map.begin ();
|
for (binding_cluster::iterator_t bind_iter = cluster->m_map.begin ();
|
||||||
bind_iter != cluster->m_map.end (); ++bind_iter)
|
bind_iter != cluster->m_map.end (); ++bind_iter)
|
||||||
{
|
{
|
||||||
const binding_key *key = (*bind_iter).first;
|
const binding_key *key = (*bind_iter).m_key;
|
||||||
const svalue *sval = (*bind_iter).second;
|
const svalue *sval = (*bind_iter).m_sval;
|
||||||
if (sval->get_kind () == SK_WIDENING)
|
if (sval->get_kind () == SK_WIDENING)
|
||||||
{
|
{
|
||||||
binding_cluster *this_cluster
|
binding_cluster *this_cluster
|
||||||
= get_or_create_cluster (base_reg);
|
= get_or_create_cluster (*mgr->get_store_manager (),
|
||||||
|
base_reg);
|
||||||
const svalue *unknown
|
const svalue *unknown
|
||||||
= mgr->get_or_create_unknown_svalue (sval->get_type ());
|
= mgr->get_or_create_unknown_svalue (sval->get_type ());
|
||||||
this_cluster->bind_key (key, unknown);
|
this_cluster->bind_key (key, unknown);
|
||||||
|
@ -3505,7 +3680,7 @@ store::replay_call_summary_cluster (call_summary_replay &r,
|
||||||
&& !caller_base_reg->symbolic_for_unknown_ptr_p ())
|
&& !caller_base_reg->symbolic_for_unknown_ptr_p ())
|
||||||
{
|
{
|
||||||
binding_cluster *caller_cluster
|
binding_cluster *caller_cluster
|
||||||
= get_or_create_cluster (caller_base_reg);
|
= get_or_create_cluster (*mgr, caller_base_reg);
|
||||||
if (summary_cluster->escaped_p ())
|
if (summary_cluster->escaped_p ())
|
||||||
caller_cluster->mark_as_escaped ();
|
caller_cluster->mark_as_escaped ();
|
||||||
if (summary_cluster->touched_p ())
|
if (summary_cluster->touched_p ())
|
||||||
|
@ -3830,6 +4005,22 @@ test_binding_key_overlap ()
|
||||||
ASSERT_DISJOINT (cb_8_23, cb_24_31);
|
ASSERT_DISJOINT (cb_8_23, cb_24_31);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_binding_map_ops ()
|
||||||
|
{
|
||||||
|
region_model_manager region_mgr;
|
||||||
|
store_manager store_mgr (®ion_mgr);
|
||||||
|
|
||||||
|
/* Assignment of empty. */
|
||||||
|
{
|
||||||
|
binding_map src (store_mgr);
|
||||||
|
binding_map dst (store_mgr);
|
||||||
|
dst = src;
|
||||||
|
|
||||||
|
ASSERT_EQ (src, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Run all of the selftests within this file. */
|
/* Run all of the selftests within this file. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3838,6 +4029,7 @@ analyzer_store_cc_tests ()
|
||||||
test_bit_range_intersects_p ();
|
test_bit_range_intersects_p ();
|
||||||
test_bit_range_from_mask ();
|
test_bit_range_from_mask ();
|
||||||
test_binding_key_overlap ();
|
test_binding_key_overlap ();
|
||||||
|
test_binding_map_ops ();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace selftest
|
} // namespace selftest
|
||||||
|
|
|
@ -512,15 +512,99 @@ template <> struct default_hash_traits<ana::symbolic_binding>
|
||||||
namespace ana {
|
namespace ana {
|
||||||
|
|
||||||
/* A mapping from binding_keys to svalues, for use by binding_cluster
|
/* A mapping from binding_keys to svalues, for use by binding_cluster
|
||||||
and compound_svalue. */
|
and compound_svalue.
|
||||||
|
We store a map from concrete keys to svalues, which is ordered by
|
||||||
|
the start offset.
|
||||||
|
We also store a vector of (symbolic key, svalue) pairs, but for now
|
||||||
|
this has maximum length of 1. */
|
||||||
|
|
||||||
class binding_map
|
class binding_map
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef hash_map <const binding_key *, const svalue *> map_t;
|
struct symbolic_binding
|
||||||
typedef map_t::iterator iterator_t;
|
{
|
||||||
|
bool operator== (const symbolic_binding &other) const
|
||||||
|
{
|
||||||
|
return (m_region == other.m_region
|
||||||
|
&& m_sval == other.m_sval);
|
||||||
|
}
|
||||||
|
|
||||||
binding_map () : m_map () {}
|
const region *m_region;
|
||||||
|
const svalue *m_sval;
|
||||||
|
};
|
||||||
|
using concrete_bindings_t = std::map<bit_range, const svalue *>;
|
||||||
|
using symbolic_bindings_t = std::vector<symbolic_binding>;
|
||||||
|
|
||||||
|
struct binding_pair
|
||||||
|
{
|
||||||
|
binding_pair (const binding_key *key,
|
||||||
|
const svalue *sval)
|
||||||
|
: m_key (key),
|
||||||
|
m_sval (sval)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const binding_key *m_key;
|
||||||
|
const svalue *m_sval;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef class const_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const_iterator (const binding_map &map,
|
||||||
|
concrete_bindings_t::const_iterator concrete_iter,
|
||||||
|
symbolic_bindings_t::const_iterator symbolic_iter)
|
||||||
|
: m_map (map),
|
||||||
|
m_concrete (concrete_iter),
|
||||||
|
m_symbolic (symbolic_iter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool operator== (const const_iterator &other) const;
|
||||||
|
bool operator!= (const const_iterator &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
const_iterator &operator++ ();
|
||||||
|
|
||||||
|
binding_pair operator* ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const binding_map &m_map;
|
||||||
|
concrete_bindings_t::const_iterator m_concrete;
|
||||||
|
symbolic_bindings_t::const_iterator m_symbolic;
|
||||||
|
} const_iterator_t;
|
||||||
|
|
||||||
|
typedef class iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class binding_map;
|
||||||
|
|
||||||
|
iterator (const binding_map &map,
|
||||||
|
concrete_bindings_t::iterator concrete_iter,
|
||||||
|
symbolic_bindings_t::iterator symbolic_iter)
|
||||||
|
: m_map (map),
|
||||||
|
m_concrete (concrete_iter),
|
||||||
|
m_symbolic (symbolic_iter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool operator== (const iterator &other) const;
|
||||||
|
bool operator!= (const iterator &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
iterator &operator++ ();
|
||||||
|
|
||||||
|
binding_pair operator* ();
|
||||||
|
|
||||||
|
const binding_key *get_key () const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const binding_map &m_map;
|
||||||
|
concrete_bindings_t::iterator m_concrete;
|
||||||
|
symbolic_bindings_t::iterator m_symbolic;
|
||||||
|
} iterator_t;
|
||||||
|
|
||||||
|
binding_map (store_manager &store_mgr);
|
||||||
binding_map (const binding_map &other);
|
binding_map (const binding_map &other);
|
||||||
binding_map& operator=(const binding_map &other);
|
binding_map& operator=(const binding_map &other);
|
||||||
|
|
||||||
|
@ -532,26 +616,27 @@ public:
|
||||||
|
|
||||||
hashval_t hash () const;
|
hashval_t hash () const;
|
||||||
|
|
||||||
const svalue *get (const binding_key *key) const
|
const svalue *get (const binding_key *key) const;
|
||||||
|
void put (const binding_key *k, const svalue *v);
|
||||||
|
void overwrite (iterator_t &pos, const svalue *v);
|
||||||
|
|
||||||
|
void remove (const binding_key *k);
|
||||||
|
void clear ()
|
||||||
{
|
{
|
||||||
const svalue **slot = const_cast<map_t &> (m_map).get (key);
|
m_concrete.clear ();
|
||||||
if (slot)
|
m_symbolic.clear ();
|
||||||
return *slot;
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
bool put (const binding_key *k, const svalue *v)
|
|
||||||
{
|
|
||||||
gcc_assert (v);
|
|
||||||
return m_map.put (k, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove (const binding_key *k) { m_map.remove (k); }
|
bool empty_p () const
|
||||||
void empty () { m_map.empty (); }
|
{
|
||||||
|
return m_concrete.empty () && m_symbolic.empty ();
|
||||||
|
}
|
||||||
|
|
||||||
iterator_t begin () const { return m_map.begin (); }
|
const_iterator_t begin () const;
|
||||||
iterator_t end () const { return m_map.end (); }
|
const_iterator_t end () const;
|
||||||
size_t elements () const { return m_map.elements (); }
|
iterator_t begin ();
|
||||||
|
iterator_t end ();
|
||||||
|
size_t elements () const;
|
||||||
|
|
||||||
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
|
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
|
||||||
void dump (bool simple) const;
|
void dump (bool simple) const;
|
||||||
|
@ -583,16 +668,11 @@ private:
|
||||||
region_model_manager *mgr,
|
region_model_manager *mgr,
|
||||||
tree index, tree val);
|
tree index, tree val);
|
||||||
|
|
||||||
map_t m_map;
|
store_manager &m_store_mgr;
|
||||||
|
concrete_bindings_t m_concrete;
|
||||||
|
symbolic_bindings_t m_symbolic;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Concept: BindingVisitor, for use by binding_cluster::for_each_binding
|
|
||||||
and store::for_each_binding.
|
|
||||||
|
|
||||||
Should implement:
|
|
||||||
void on_binding (const binding_key *key, const svalue *&sval);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* All of the bindings within a store for regions that share the same
|
/* All of the bindings within a store for regions that share the same
|
||||||
base region. */
|
base region. */
|
||||||
|
|
||||||
|
@ -601,10 +681,10 @@ class binding_cluster
|
||||||
public:
|
public:
|
||||||
friend class store;
|
friend class store;
|
||||||
|
|
||||||
typedef hash_map <const binding_key *, const svalue *> map_t;
|
typedef binding_map::const_iterator const_iterator_t;
|
||||||
typedef map_t::iterator iterator_t;
|
typedef binding_map::iterator iterator_t;
|
||||||
|
|
||||||
binding_cluster (const region *base_region);
|
binding_cluster (store_manager &store_mgr, const region *base_region);
|
||||||
binding_cluster (const binding_cluster &other);
|
binding_cluster (const binding_cluster &other);
|
||||||
binding_cluster& operator=(const binding_cluster &other);
|
binding_cluster& operator=(const binding_cluster &other);
|
||||||
|
|
||||||
|
@ -661,8 +741,8 @@ public:
|
||||||
void for_each_value (void (*cb) (const svalue *sval, T user_data),
|
void for_each_value (void (*cb) (const svalue *sval, T user_data),
|
||||||
T user_data) const
|
T user_data) const
|
||||||
{
|
{
|
||||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
for (auto iter : m_map)
|
||||||
cb ((*iter).second, user_data);
|
cb (iter.m_sval, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool can_merge_p (const binding_cluster *cluster_a,
|
static bool can_merge_p (const binding_cluster *cluster_a,
|
||||||
|
@ -685,7 +765,7 @@ public:
|
||||||
bool touched_p () const { return m_touched; }
|
bool touched_p () const { return m_touched; }
|
||||||
|
|
||||||
bool redundant_p () const;
|
bool redundant_p () const;
|
||||||
bool empty_p () const { return m_map.elements () == 0; }
|
bool empty_p () const { return m_map.empty_p (); }
|
||||||
|
|
||||||
void get_representative_path_vars (const region_model *model,
|
void get_representative_path_vars (const region_model *model,
|
||||||
svalue_set *visited,
|
svalue_set *visited,
|
||||||
|
@ -696,21 +776,14 @@ public:
|
||||||
|
|
||||||
const svalue *maybe_get_simple_value (store_manager *mgr) const;
|
const svalue *maybe_get_simple_value (store_manager *mgr) const;
|
||||||
|
|
||||||
template <typename BindingVisitor>
|
const_iterator_t begin () const { return m_map.begin (); }
|
||||||
void for_each_binding (BindingVisitor &v) const
|
const_iterator_t end () const { return m_map.end (); }
|
||||||
{
|
|
||||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
|
||||||
{
|
|
||||||
const binding_key *key = (*iter).first;
|
|
||||||
const svalue *&sval = (*iter).second;
|
|
||||||
v.on_binding (key, sval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator_t begin () const { return m_map.begin (); }
|
iterator_t begin () { return m_map.begin (); }
|
||||||
iterator_t end () const { return m_map.end (); }
|
iterator_t end () { return m_map.end (); }
|
||||||
|
|
||||||
const binding_map &get_map () const { return m_map; }
|
const binding_map &get_map () const { return m_map; }
|
||||||
|
binding_map &get_map () { return m_map; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const svalue *get_any_value (const binding_key *key) const;
|
const svalue *get_any_value (const binding_key *key) const;
|
||||||
|
@ -793,7 +866,8 @@ public:
|
||||||
|
|
||||||
const binding_cluster *get_cluster (const region *base_reg) const;
|
const binding_cluster *get_cluster (const region *base_reg) const;
|
||||||
binding_cluster *get_cluster (const region *base_reg);
|
binding_cluster *get_cluster (const region *base_reg);
|
||||||
binding_cluster *get_or_create_cluster (const region *base_reg);
|
binding_cluster *get_or_create_cluster (store_manager &store_mgr,
|
||||||
|
const region *base_reg);
|
||||||
void purge_cluster (const region *base_reg);
|
void purge_cluster (const region *base_reg);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -809,7 +883,7 @@ public:
|
||||||
store *out_store, store_manager *mgr,
|
store *out_store, store_manager *mgr,
|
||||||
model_merger *merger);
|
model_merger *merger);
|
||||||
|
|
||||||
void mark_as_escaped (const region *base_reg);
|
void mark_as_escaped (store_manager &mgr, const region *base_reg);
|
||||||
void on_unknown_fncall (const gcall &call, store_manager *mgr,
|
void on_unknown_fncall (const gcall &call, store_manager *mgr,
|
||||||
const conjured_purge &p);
|
const conjured_purge &p);
|
||||||
bool escaped_p (const region *reg) const;
|
bool escaped_p (const region *reg) const;
|
||||||
|
@ -826,14 +900,6 @@ public:
|
||||||
tristate eval_alias (const region *base_reg_a,
|
tristate eval_alias (const region *base_reg_a,
|
||||||
const region *base_reg_b) const;
|
const region *base_reg_b) const;
|
||||||
|
|
||||||
template <typename BindingVisitor>
|
|
||||||
void for_each_binding (BindingVisitor &v)
|
|
||||||
{
|
|
||||||
for (cluster_map_t::iterator iter = m_cluster_map.begin ();
|
|
||||||
iter != m_cluster_map.end (); ++iter)
|
|
||||||
(*iter).second->for_each_binding (v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void canonicalize (store_manager *mgr);
|
void canonicalize (store_manager *mgr);
|
||||||
void loop_replay_fixup (const store *other_store,
|
void loop_replay_fixup (const store *other_store,
|
||||||
region_model_manager *mgr);
|
region_model_manager *mgr);
|
||||||
|
@ -843,7 +909,8 @@ public:
|
||||||
void replay_call_summary_cluster (call_summary_replay &r,
|
void replay_call_summary_cluster (call_summary_replay &r,
|
||||||
const store &summary,
|
const store &summary,
|
||||||
const region *base_reg);
|
const region *base_reg);
|
||||||
void on_maybe_live_values (const svalue_set &maybe_live_values);
|
void on_maybe_live_values (store_manager &mgr,
|
||||||
|
const svalue_set &maybe_live_values);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void remove_overlapping_bindings (store_manager *mgr, const region *reg,
|
void remove_overlapping_bindings (store_manager *mgr, const region *reg,
|
||||||
|
|
|
@ -2232,15 +2232,15 @@ compound_svalue::compound_svalue (symbol::id_t id,
|
||||||
: svalue (calc_complexity (map), id, type), m_map (map)
|
: svalue (calc_complexity (map), id, type), m_map (map)
|
||||||
{
|
{
|
||||||
#if CHECKING_P
|
#if CHECKING_P
|
||||||
for (iterator_t iter = begin (); iter != end (); ++iter)
|
for (auto iter : *this)
|
||||||
{
|
{
|
||||||
/* All keys within the underlying binding_map are required to be concrete,
|
/* All keys within the underlying binding_map are required to be concrete,
|
||||||
not symbolic. */
|
not symbolic. */
|
||||||
const binding_key *key = (*iter).first;
|
const binding_key *key = iter.m_key;
|
||||||
gcc_assert (key->concrete_p ());
|
gcc_assert (key->concrete_p ());
|
||||||
|
|
||||||
/* We don't nest compound svalues. */
|
/* We don't nest compound svalues. */
|
||||||
const svalue *sval = (*iter).second;
|
const svalue *sval = iter.m_sval;
|
||||||
gcc_assert (sval->get_kind () != SK_COMPOUND);
|
gcc_assert (sval->get_kind () != SK_COMPOUND);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2302,11 +2302,10 @@ add_dump_widget_children (text_art::tree_widget &w,
|
||||||
void
|
void
|
||||||
compound_svalue::accept (visitor *v) const
|
compound_svalue::accept (visitor *v) const
|
||||||
{
|
{
|
||||||
for (binding_map::iterator_t iter = m_map.begin ();
|
for (auto iter : m_map)
|
||||||
iter != m_map.end (); ++iter)
|
|
||||||
{
|
{
|
||||||
//(*iter).first.accept (v);
|
//iter.first.accept (v);
|
||||||
(*iter).second->accept (v);
|
iter.m_sval->accept (v);
|
||||||
}
|
}
|
||||||
v->visit_compound_svalue (this);
|
v->visit_compound_svalue (this);
|
||||||
}
|
}
|
||||||
|
@ -2319,10 +2318,9 @@ compound_svalue::calc_complexity (const binding_map &map)
|
||||||
{
|
{
|
||||||
unsigned num_child_nodes = 0;
|
unsigned num_child_nodes = 0;
|
||||||
unsigned max_child_depth = 0;
|
unsigned max_child_depth = 0;
|
||||||
for (binding_map::iterator_t iter = map.begin ();
|
for (auto iter : map)
|
||||||
iter != map.end (); ++iter)
|
|
||||||
{
|
{
|
||||||
const complexity &sval_c = (*iter).second->get_complexity ();
|
const complexity &sval_c = iter.m_sval->get_complexity ();
|
||||||
num_child_nodes += sval_c.m_num_nodes;
|
num_child_nodes += sval_c.m_num_nodes;
|
||||||
max_child_depth = MAX (max_child_depth, sval_c.m_max_depth);
|
max_child_depth = MAX (max_child_depth, sval_c.m_max_depth);
|
||||||
}
|
}
|
||||||
|
@ -2337,10 +2335,10 @@ compound_svalue::maybe_fold_bits_within (tree type,
|
||||||
const bit_range &bits,
|
const bit_range &bits,
|
||||||
region_model_manager *mgr) const
|
region_model_manager *mgr) const
|
||||||
{
|
{
|
||||||
binding_map result_map;
|
binding_map result_map (*mgr->get_store_manager ());
|
||||||
for (auto iter : m_map)
|
for (auto iter : m_map)
|
||||||
{
|
{
|
||||||
const binding_key *key = iter.first;
|
const binding_key *key = iter.m_key;
|
||||||
if (const concrete_binding *conc_key
|
if (const concrete_binding *conc_key
|
||||||
= key->dyn_cast_concrete_binding ())
|
= key->dyn_cast_concrete_binding ())
|
||||||
{
|
{
|
||||||
|
@ -2348,7 +2346,7 @@ compound_svalue::maybe_fold_bits_within (tree type,
|
||||||
if (!conc_key->get_bit_range ().intersects_p (bits))
|
if (!conc_key->get_bit_range ().intersects_p (bits))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.m_sval;
|
||||||
/* Get the position of conc_key relative to BITS. */
|
/* Get the position of conc_key relative to BITS. */
|
||||||
bit_range result_location (conc_key->get_start_bit_offset ()
|
bit_range result_location (conc_key->get_start_bit_offset ()
|
||||||
- bits.get_start_bit_offset (),
|
- bits.get_start_bit_offset (),
|
||||||
|
|
|
@ -1391,6 +1391,7 @@ namespace ana {
|
||||||
class compound_svalue : public svalue
|
class compound_svalue : public svalue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef binding_map::const_iterator_t const_iterator_t;
|
||||||
typedef binding_map::iterator_t iterator_t;
|
typedef binding_map::iterator_t iterator_t;
|
||||||
|
|
||||||
/* A support class for uniquifying instances of compound_svalue.
|
/* A support class for uniquifying instances of compound_svalue.
|
||||||
|
@ -1445,8 +1446,10 @@ public:
|
||||||
|
|
||||||
const binding_map &get_map () const { return m_map; }
|
const binding_map &get_map () const { return m_map; }
|
||||||
|
|
||||||
iterator_t begin () const { return m_map.begin (); }
|
const_iterator_t begin () const { return m_map.begin (); }
|
||||||
iterator_t end () const { return m_map.end (); }
|
const_iterator_t end () const { return m_map.end (); }
|
||||||
|
iterator_t begin () { return m_map.begin (); }
|
||||||
|
iterator_t end () { return m_map.end (); }
|
||||||
|
|
||||||
struct key_t make_key () const
|
struct key_t make_key () const
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
/* -fanalyzer plugin for CPython extension modules */
|
/* -fanalyzer plugin for CPython extension modules */
|
||||||
/* { dg-options "-g" } */
|
/* { dg-options "-g" } */
|
||||||
|
|
||||||
#define INCLUDE_MEMORY
|
#include "analyzer/common.h"
|
||||||
#define INCLUDE_STRING
|
|
||||||
#define INCLUDE_VECTOR
|
|
||||||
#include "gcc-plugin.h"
|
#include "gcc-plugin.h"
|
||||||
#include "config.h"
|
|
||||||
#include "system.h"
|
|
||||||
#include "coretypes.h"
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
#include "basic-block.h"
|
#include "basic-block.h"
|
||||||
|
@ -416,7 +411,7 @@ count_pyobj_references (const region_model *model,
|
||||||
|
|
||||||
for (const auto &binding : retval_binding_map)
|
for (const auto &binding : retval_binding_map)
|
||||||
{
|
{
|
||||||
const svalue *binding_sval = binding.second;
|
const svalue *binding_sval = binding.m_sval;
|
||||||
const svalue *unwrapped_sval = binding_sval->unwrap_any_unmergeable ();
|
const svalue *unwrapped_sval = binding_sval->unwrap_any_unmergeable ();
|
||||||
const region *pointee = unwrapped_sval->maybe_get_region ();
|
const region *pointee = unwrapped_sval->maybe_get_region ();
|
||||||
|
|
||||||
|
@ -506,7 +501,7 @@ count_all_references (const region_model *model,
|
||||||
auto binding_cluster = cluster.second;
|
auto binding_cluster = cluster.second;
|
||||||
for (const auto &binding : binding_cluster->get_map ())
|
for (const auto &binding : binding_cluster->get_map ())
|
||||||
{
|
{
|
||||||
const svalue *binding_sval = binding.second;
|
const svalue *binding_sval = binding.m_sval;
|
||||||
|
|
||||||
const svalue *unwrapped_sval
|
const svalue *unwrapped_sval
|
||||||
= binding_sval->unwrap_any_unmergeable ();
|
= binding_sval->unwrap_any_unmergeable ();
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
/* Proof-of-concept of a -fanalyzer plugin for the Linux kernel. */
|
/* Proof-of-concept of a -fanalyzer plugin for the Linux kernel. */
|
||||||
/* { dg-options "-g" } */
|
/* { dg-options "-g" } */
|
||||||
|
|
||||||
#define INCLUDE_MEMORY
|
#include "analyzer/common.h"
|
||||||
#define INCLUDE_STRING
|
|
||||||
#define INCLUDE_VECTOR
|
|
||||||
#include "gcc-plugin.h"
|
#include "gcc-plugin.h"
|
||||||
#include "config.h"
|
|
||||||
#include "system.h"
|
|
||||||
#include "coretypes.h"
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
#include "basic-block.h"
|
#include "basic-block.h"
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
/* Proof-of-concept of a -fanalyzer plugin to handle known functions. */
|
/* Proof-of-concept of a -fanalyzer plugin to handle known functions. */
|
||||||
/* { dg-options "-g" } */
|
/* { dg-options "-g" } */
|
||||||
|
|
||||||
#define INCLUDE_MEMORY
|
#include "analyzer/common.h"
|
||||||
#define INCLUDE_STRING
|
|
||||||
#define INCLUDE_VECTOR
|
|
||||||
#include "gcc-plugin.h"
|
#include "gcc-plugin.h"
|
||||||
#include "config.h"
|
|
||||||
#include "system.h"
|
|
||||||
#include "coretypes.h"
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
#include "basic-block.h"
|
#include "basic-block.h"
|
||||||
|
|
Loading…
Reference in New Issue