aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/program-state.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/analyzer/program-state.cc')
-rw-r--r--gcc/analyzer/program-state.cc145
1 files changed, 121 insertions, 24 deletions
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 5bb8907..5c59c09 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -131,12 +131,31 @@ extrinsic_state::get_model_manager () const
return NULL; /* for selftests. */
}
+/* struct sm_state_map::entry_t. */
+
+int
+sm_state_map::entry_t::cmp (const entry_t &entry_a, const entry_t &entry_b)
+{
+ gcc_assert (entry_a.m_state);
+ gcc_assert (entry_b.m_state);
+ if (int cmp_state = ((int)entry_a.m_state->get_id ()
+ - (int)entry_b.m_state->get_id ()))
+ return cmp_state;
+ if (entry_a.m_origin && entry_b.m_origin)
+ return svalue::cmp_ptr (entry_a.m_origin, entry_b.m_origin);
+ if (entry_a.m_origin)
+ return 1;
+ if (entry_b.m_origin)
+ return -1;
+ return 0;
+}
+
/* class sm_state_map. */
/* sm_state_map's ctor. */
-sm_state_map::sm_state_map (const state_machine &sm, int sm_idx)
-: m_sm (sm), m_sm_idx (sm_idx), m_map (), m_global_state (sm.get_start_state ())
+sm_state_map::sm_state_map (const state_machine &sm)
+: m_sm (sm), m_map (), m_global_state (sm.get_start_state ())
{
}
@@ -170,21 +189,29 @@ sm_state_map::print (const region_model *model,
pp_newline (pp);
first = false;
}
+ auto_vec <const svalue *> keys (m_map.elements ());
for (map_t::iterator iter = m_map.begin ();
iter != m_map.end ();
++iter)
+ keys.quick_push ((*iter).first);
+ keys.qsort (svalue::cmp_ptr_ptr);
+ unsigned i;
+ const svalue *sval;
+ FOR_EACH_VEC_ELT (keys, i, sval)
{
if (multiline)
pp_string (pp, " ");
else if (!first)
pp_string (pp, ", ");
first = false;
- const svalue *sval = (*iter).first;
- pp_pointer (pp, sval);
- pp_string (pp, ": ");
+ if (!flag_dump_noaddr)
+ {
+ pp_pointer (pp, sval);
+ pp_string (pp, ": ");
+ }
sval->dump_to_pp (pp, simple);
- entry_t e = (*iter).second;
+ entry_t e = *const_cast <map_t &> (m_map).get (sval);
pp_string (pp, ": ");
e.m_state->dump_to_pp (pp);
if (model)
@@ -197,8 +224,11 @@ sm_state_map::print (const region_model *model,
if (e.m_origin)
{
pp_string (pp, " (origin: ");
- pp_pointer (pp, e.m_origin);
- pp_string (pp, ": ");
+ if (!flag_dump_noaddr)
+ {
+ pp_pointer (pp, e.m_origin);
+ pp_string (pp, ": ");
+ }
e.m_origin->dump_to_pp (pp, simple);
if (model)
if (tree rep = model->get_representative_tree (e.m_origin))
@@ -487,6 +517,7 @@ sm_state_map::on_liveness_change (const svalue_set &live_svalues,
{
svalue_set svals_to_unset;
+ auto_vec<const svalue *> leaked_svals (m_map.elements ());
for (map_t::iterator iter = m_map.begin ();
iter != m_map.end ();
++iter)
@@ -497,10 +528,20 @@ sm_state_map::on_liveness_change (const svalue_set &live_svalues,
svals_to_unset.add (iter_sval);
entry_t e = (*iter).second;
if (!m_sm.can_purge_p (e.m_state))
- ctxt->on_state_leak (m_sm, iter_sval, e.m_state);
+ leaked_svals.quick_push (iter_sval);
}
}
+ leaked_svals.qsort (svalue::cmp_ptr_ptr);
+
+ unsigned i;
+ const svalue *sval;
+ FOR_EACH_VEC_ELT (leaked_svals, i, sval)
+ {
+ entry_t e = *m_map.get (sval);
+ ctxt->on_state_leak (m_sm, sval, e.m_state);
+ }
+
for (svalue_set::iterator iter = svals_to_unset.begin ();
iter != svals_to_unset.end (); ++iter)
m_map.remove (*iter);
@@ -545,6 +586,44 @@ sm_state_map::on_unknown_change (const svalue *sval,
impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state);
}
+/* Comparator for imposing an order on sm_state_map instances. */
+
+int
+sm_state_map::cmp (const sm_state_map &smap_a, const sm_state_map &smap_b)
+{
+ if (int cmp_count = smap_a.elements () - smap_b.elements ())
+ return cmp_count;
+
+ auto_vec <const svalue *> keys_a (smap_a.elements ());
+ for (map_t::iterator iter = smap_a.begin ();
+ iter != smap_a.end ();
+ ++iter)
+ keys_a.quick_push ((*iter).first);
+ keys_a.qsort (svalue::cmp_ptr_ptr);
+
+ auto_vec <const svalue *> keys_b (smap_b.elements ());
+ for (map_t::iterator iter = smap_b.begin ();
+ iter != smap_b.end ();
+ ++iter)
+ keys_b.quick_push ((*iter).first);
+ keys_b.qsort (svalue::cmp_ptr_ptr);
+
+ unsigned i;
+ const svalue *sval_a;
+ FOR_EACH_VEC_ELT (keys_a, i, sval_a)
+ {
+ const svalue *sval_b = keys_b[i];
+ if (int cmp_sval = svalue::cmp_ptr (sval_a, sval_b))
+ return cmp_sval;
+ const entry_t *e_a = const_cast <map_t &> (smap_a.m_map).get (sval_a);
+ const entry_t *e_b = const_cast <map_t &> (smap_b.m_map).get (sval_b);
+ if (int cmp_entry = entry_t::cmp (*e_a, *e_b))
+ return cmp_entry;
+ }
+
+ return 0;
+}
+
/* Canonicalize SVAL before getting/setting it within the map.
Convert all NULL pointers to (void *) to avoid state explosions
involving all of the various (foo *)NULL vs (bar *)NULL. */
@@ -577,7 +656,7 @@ program_state::program_state (const extrinsic_state &ext_state)
const int num_states = ext_state.get_num_checkers ();
for (int i = 0; i < num_states; i++)
{
- sm_state_map *sm = new sm_state_map (ext_state.get_sm (i), i);
+ sm_state_map *sm = new sm_state_map (ext_state.get_sm (i));
m_checker_states.quick_push (sm);
}
}
@@ -916,6 +995,7 @@ program_state::prune_for_point (exploded_graph &eg,
auto_vec<const decl_region *> ssa_name_regs;
new_state.m_region_model->get_ssa_name_regions_for_current_frame
(&ssa_name_regs);
+ ssa_name_regs.qsort (region::cmp_ptr_ptr);
unsigned i;
const decl_region *reg;
FOR_EACH_VEC_ELT (ssa_name_regs, i, reg)
@@ -1032,18 +1112,26 @@ program_state::validate (const extrinsic_state &ext_state) const
static void
log_set_of_svalues (logger *logger, const char *name,
- const svalue_set &set)
+ const svalue_set &set)
{
logger->log (name);
logger->inc_indent ();
+ auto_vec<const svalue *> sval_vecs (set.elements ());
for (svalue_set::iterator iter = set.begin ();
iter != set.end (); ++iter)
+ sval_vecs.quick_push (*iter);
+ sval_vecs.qsort (svalue::cmp_ptr_ptr);
+ unsigned i;
+ const svalue *sval;
+ FOR_EACH_VEC_ELT (sval_vecs, i, sval)
{
logger->start_log_line ();
pretty_printer *pp = logger->get_printer ();
- const svalue *sval = (*iter);
- pp_pointer (pp, sval);
- pp_string (pp, ": ");
+ if (!flag_dump_noaddr)
+ {
+ pp_pointer (pp, sval);
+ pp_string (pp, ": ");
+ }
sval->dump_to_pp (pp, false);
logger->end_log_line ();
}
@@ -1104,6 +1192,7 @@ program_state::detect_leaks (const program_state &src_state,
dest_svalues);
}
+ auto_vec <const svalue *> dead_svals (src_svalues.elements ());
for (svalue_set::iterator iter = src_svalues.begin ();
iter != src_svalues.end (); ++iter)
{
@@ -1111,11 +1200,19 @@ program_state::detect_leaks (const program_state &src_state,
/* For each sval reachable from SRC_STATE, determine if it is
live in DEST_STATE: either explicitly reachable, or implicitly
live based on the set of explicitly reachable svalues.
- Call CTXT->on_svalue_leak on those that have ceased to be live. */
+ Record those that have ceased to be live. */
if (!sval->live_p (dest_svalues, dest_state.m_region_model))
- ctxt->on_svalue_leak (sval);
+ dead_svals.quick_push (sval);
}
+ /* Call CTXT->on_svalue_leak on all svals in SRC_STATE that have ceased
+ to be live, sorting them first to ensure deterministic behavior. */
+ dead_svals.qsort (svalue::cmp_ptr_ptr);
+ unsigned i;
+ const svalue *sval;
+ FOR_EACH_VEC_ELT (dead_svals, i, sval)
+ ctxt->on_svalue_leak (sval);
+
/* Purge dead svals from sm-state. */
ctxt->on_liveness_change (dest_svalues, dest_state.m_region_model);
@@ -1154,7 +1251,7 @@ test_sm_state_map ()
const svalue *y_sval = model.get_rvalue (y, NULL);
const svalue *z_sval = model.get_rvalue (z, NULL);
- sm_state_map map (*sm, 0);
+ sm_state_map map (*sm);
ASSERT_TRUE (map.is_empty_p ());
ASSERT_EQ (map.get_state (x_sval, ext_state), start);
@@ -1183,7 +1280,7 @@ test_sm_state_map ()
const svalue *y_sval = model.get_rvalue (y, NULL);
const svalue *z_sval = model.get_rvalue (z, NULL);
- sm_state_map map (*sm, 0);
+ sm_state_map map (*sm);
ASSERT_TRUE (map.is_empty_p ());
ASSERT_EQ (map.get_state (x_sval, ext_state), start);
ASSERT_EQ (map.get_state (y_sval, ext_state), start);
@@ -1206,9 +1303,9 @@ test_sm_state_map ()
const svalue *y_sval = model.get_rvalue (y, NULL);
const svalue *z_sval = model.get_rvalue (z, NULL);
- sm_state_map map0 (*sm, 0);
- sm_state_map map1 (*sm, 0);
- sm_state_map map2 (*sm, 0);
+ sm_state_map map0 (*sm);
+ sm_state_map map1 (*sm);
+ sm_state_map map2 (*sm);
ASSERT_EQ (map0.hash (), map1.hash ());
ASSERT_EQ (map0, map1);
@@ -1229,9 +1326,9 @@ test_sm_state_map ()
const state_machine::state_t TEST_STATE_2 = &test_state_2;
const state_machine::state test_state_3 ("test state 3", 3);
const state_machine::state_t TEST_STATE_3 = &test_state_3;
- sm_state_map map0 (*sm, 0);
- sm_state_map map1 (*sm, 0);
- sm_state_map map2 (*sm, 0);
+ sm_state_map map0 (*sm);
+ sm_state_map map1 (*sm);
+ sm_state_map map2 (*sm);
ASSERT_EQ (map0.hash (), map1.hash ());
ASSERT_EQ (map0, map1);