diff options
Diffstat (limited to 'gcc/analyzer/program-state.cc')
-rw-r--r-- | gcc/analyzer/program-state.cc | 240 |
1 files changed, 122 insertions, 118 deletions
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index ec96900..e16a50f 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -18,44 +18,39 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "diagnostic-core.h" -#include "diagnostic.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" -#include "analyzer/sm.h" +#include "analyzer/common.h" + #include "sbitmap.h" -#include "bitmap.h" #include "ordered-hash-map.h" #include "selftest.h" +#include "cfg.h" +#include "gimple-iterator.h" +#include "cgraph.h" +#include "digraph.h" +#include "diagnostics/event-id.h" +#include "diagnostics/state-graphs.h" +#include "graphviz.h" + +#include "text-art/tree-widget.h" +#include "text-art/dump.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/sm.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/constraint-manager.h" -#include "diagnostic-event-id.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" #include "analyzer/state-purge.h" #include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" -#include "text-art/tree-widget.h" -#include "text-art/dump.h" -#include "make-unique.h" +#include "analyzer/ana-state-to-diagnostic-state.h" #if ENABLE_ANALYZER @@ -69,11 +64,10 @@ void extrinsic_state::dump_to_pp (pretty_printer *pp) const { pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ()); - unsigned i; - state_machine *checker; - FOR_EACH_VEC_ELT (m_checkers, i, checker) + unsigned i = 0; + for (auto &checker : m_checkers) { - pp_printf (pp, "m_checkers[%i]: %qs\n", i, checker->get_name ()); + pp_printf (pp, "m_checkers[%i]: %qs\n", ++i, checker->get_name ()); checker->dump_to_pp (pp); } } @@ -101,13 +95,11 @@ extrinsic_state::dump () const std::unique_ptr<json::object> extrinsic_state::to_json () const { - auto ext_state_obj = ::make_unique<json::object> (); + auto ext_state_obj = std::make_unique<json::object> (); { - auto checkers_arr = ::make_unique<json::array> (); - unsigned i; - state_machine *sm; - FOR_EACH_VEC_ELT (m_checkers, i, sm) + auto checkers_arr = std::make_unique<json::array> (); + for (auto &sm : m_checkers) checkers_arr->append (sm->to_json ()); ext_state_obj->set ("checkers", std::move (checkers_arr)); } @@ -123,7 +115,7 @@ extrinsic_state::get_model_manager () const if (m_engine) return m_engine->get_model_manager (); else - return NULL; /* for selftests. */ + return nullptr; /* for selftests. */ } /* Try to find a state machine named NAME. @@ -133,10 +125,8 @@ extrinsic_state::get_model_manager () const bool extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const { - unsigned i; - state_machine *sm; - FOR_EACH_VEC_ELT (m_checkers, i, sm) - if (0 == strcmp (name, sm->get_name ())) + for (size_t i = 0; i < m_checkers.size (); ++i) + if (0 == strcmp (name, m_checkers[i]->get_name ())) { /* Found NAME. */ *out = i; @@ -268,7 +258,7 @@ DEBUG_FUNCTION void sm_state_map::dump (bool simple) const { tree_dump_pretty_printer pp (stderr); - print (NULL, simple, true, &pp); + print (nullptr, simple, true, &pp); pp_newline (&pp); } @@ -279,7 +269,7 @@ sm_state_map::dump (bool simple) const std::unique_ptr<json::object> sm_state_map::to_json () const { - auto map_obj = ::make_unique<json::object> (); + auto map_obj = std::make_unique<json::object> (); if (m_global_state != m_sm.get_start_state ()) map_obj->set ("global", m_global_state->to_json ()); @@ -430,7 +420,7 @@ sm_state_map::operator== (const sm_state_map &other) const const svalue *sval = (*iter).first; entry_t e = (*iter).second; entry_t *other_slot = const_cast <map_t &> (other.m_map).get (sval); - if (other_slot == NULL) + if (other_slot == nullptr) return false; if (e != *other_slot) return false; @@ -511,7 +501,7 @@ sm_state_map::get_origin (const svalue *sval, if (slot) return slot->m_origin; else - return NULL; + return nullptr; } /* Set the state of SID within MODEL to STATE, recording that @@ -524,7 +514,7 @@ sm_state_map::set_state (region_model *model, const svalue *origin, const extrinsic_state &ext_state) { - if (model == NULL) + if (model == nullptr) return; /* Reject attempts to set state on UNKNOWN/POISONED. */ @@ -781,7 +771,7 @@ sm_state_map::on_unknown_change (const svalue *sval, for (svalue_set::iterator iter = svals_to_unset.begin (); iter != svals_to_unset.end (); ++iter) - impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state); + impl_set_state (*iter, (state_machine::state_t)0, nullptr, ext_state); } /* Purge state for things involving SVAL. @@ -812,7 +802,7 @@ sm_state_map::purge_state_involving (const svalue *sval, for (svalue_set::iterator iter = svals_to_unset.begin (); iter != svals_to_unset.end (); ++iter) - impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state); + impl_set_state (*iter, (state_machine::state_t)0, nullptr, ext_state); } /* Comparator for imposing an order on sm_state_map instances. */ @@ -922,7 +912,7 @@ sm_state_map::can_merge_with_p (const sm_state_map &other, state_machine::state_t other_state = other.get_state (sval, ext_state); if (state_machine::state_t merged_state = sm.maybe_get_merged_state (this_state, other_state)) - (*out)->impl_set_state (sval, merged_state, NULL, ext_state); + (*out)->impl_set_state (sval, merged_state, nullptr, ext_state); else return false; } @@ -936,7 +926,7 @@ sm_state_map::can_merge_with_p (const sm_state_map &other, /* program_state's ctor. */ program_state::program_state (const extrinsic_state &ext_state) -: m_region_model (NULL), +: m_region_model (nullptr), m_checker_states (ext_state.get_num_checkers ()), m_valid (true) { @@ -970,8 +960,8 @@ sm_state_map::replay_call_summary (call_summary_replay &r, const svalue *caller_origin = (summary_origin ? r.convert_svalue_from_summary (summary_origin) - : NULL); - // caller_origin can be NULL. + : nullptr); + // caller_origin can be nullptr. m_map.put (caller_sval, entry_t (kv.second.m_state, caller_origin)); } m_global_state = summary.m_global_state; @@ -1019,7 +1009,7 @@ program_state::program_state (program_state &&other) : m_region_model (other.m_region_model), m_checker_states (other.m_checker_states.length ()) { - other.m_region_model = NULL; + other.m_region_model = nullptr; int i; sm_state_map *smap; @@ -1188,7 +1178,7 @@ program_state::dump () const std::unique_ptr<json::object> program_state::to_json (const extrinsic_state &ext_state) const { - auto state_obj = ::make_unique<json::object> (); + auto state_obj = std::make_unique<json::object> (); state_obj->set ("store", m_region_model->get_store ()->to_json ()); state_obj->set ("constraints", @@ -1199,7 +1189,7 @@ program_state::to_json (const extrinsic_state &ext_state) const /* Provide m_checker_states as an object, using names as keys. */ { - auto checkers_obj = ::make_unique<json::object> (); + auto checkers_obj = std::make_unique<json::object> (); int i; sm_state_map *smap; @@ -1237,6 +1227,24 @@ program_state::make_dump_widget (const text_art::dump_widget_info &dwi) const return state_widget; } +void +program_state::dump_dot (const extrinsic_state &ext_state) const +{ + auto state_graph = make_diagnostic_state_graph (ext_state); + + gcc_assert (global_dc); + auto logical_loc_mgr = global_dc->get_logical_location_manager (); + gcc_assert (logical_loc_mgr); + + auto graph = diagnostics::state_graphs::make_dot_graph (*state_graph, + *logical_loc_mgr); + + pretty_printer pp; + dot::writer w (pp); + graph->print (w); + pp_flush (&pp); +} + /* Update this program_state to reflect a top-level call to FUN. The params will have initial_svalues. */ @@ -1244,7 +1252,7 @@ void program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED, const function &fun) { - m_region_model->push_frame (fun, NULL, NULL); + m_region_model->push_frame (fun, nullptr, nullptr, nullptr); } /* Get the current function of this state. */ @@ -1335,7 +1343,7 @@ program_state::on_edge (exploded_graph &eg, return false; program_state::detect_leaks (enode->get_state (), *this, - NULL, eg.get_ext_state (), + nullptr, eg.get_ext_state (), &ctxt); return true; @@ -1348,7 +1356,7 @@ program_state::on_edge (exploded_graph &eg, void program_state::push_call (exploded_graph &eg, exploded_node *enode, - const gcall *call_stmt, + const gcall &call_stmt, uncertainty_t *uncertainty) { /* Update state. */ @@ -1359,7 +1367,7 @@ program_state::push_call (exploded_graph &eg, &enode->get_state (), this, uncertainty, - NULL, + nullptr, last_stmt); m_region_model->update_for_gcall (call_stmt, &ctxt); } @@ -1371,7 +1379,7 @@ program_state::push_call (exploded_graph &eg, void program_state::returning_call (exploded_graph &eg, exploded_node *enode, - const gcall *call_stmt, + const gcall &call_stmt, uncertainty_t *uncertainty) { /* Update state. */ @@ -1382,7 +1390,7 @@ program_state::returning_call (exploded_graph &eg, &enode->get_state (), this, uncertainty, - NULL, + nullptr, last_stmt); m_region_model->update_for_return_gcall (call_stmt, &ctxt); } @@ -1440,7 +1448,7 @@ program_state::prune_for_point (exploded_graph &eg, temporaries keep the value reachable until the frame is popped. */ const svalue *sval - = new_state.m_region_model->get_store_value (reg, NULL); + = new_state.m_region_model->get_store_value (reg, nullptr); if (!new_state.can_purge_p (eg.get_ext_state (), sval) && SSA_NAME_VAR (ssa_name)) { @@ -1499,9 +1507,9 @@ program_state::prune_for_point (exploded_graph &eg, impl_region_model_context ctxt (eg, enode_for_diag, this, &new_state, - uncertainty, NULL, + uncertainty, nullptr, point.get_stmt ()); - detect_leaks (*this, new_state, NULL, eg.get_ext_state (), &ctxt); + detect_leaks (*this, new_state, nullptr, eg.get_ext_state (), &ctxt); } } @@ -1673,7 +1681,7 @@ program_state::detect_leaks (const program_state &src_state, *might* still be reachable in dst_state. */ svalue_set known_src_svalues; src_state.m_region_model->get_reachable_svalues (&known_src_svalues, - NULL, NULL); + nullptr, nullptr); svalue_set maybe_dest_svalues; dest_state.m_region_model->get_reachable_svalues (&maybe_dest_svalues, extra_sval, uncertainty); @@ -1749,7 +1757,7 @@ program_state::replay_call_summary (call_summary_replay &r, /* Handle calls to "__analyzer_dump_state". */ void -program_state::impl_call_analyzer_dump_state (const gcall *call, +program_state::impl_call_analyzer_dump_state (const gcall &call, const extrinsic_state &ext_state, region_model_context *ctxt) { @@ -1757,13 +1765,13 @@ program_state::impl_call_analyzer_dump_state (const gcall *call, const char *sm_name = cd.get_arg_string_literal (0); if (!sm_name) { - error_at (call->location, "cannot determine state machine"); + error_at (call.location, "cannot determine state machine"); return; } unsigned sm_idx; if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx)) { - error_at (call->location, "unrecognized state machine %qs", sm_name); + error_at (call.location, "unrecognized state machine %qs", sm_name); return; } const sm_state_map *smap = m_checker_states[sm_idx]; @@ -1775,7 +1783,7 @@ program_state::impl_call_analyzer_dump_state (const gcall *call, sval = cast; state_machine::state_t state = smap->get_state (sval, ext_state); - warning_at (call->location, 0, "state: %qs", state->get_name ()); + warning_at (call.location, 0, "state: %qs", state->get_name ()); } #if CHECKING_P @@ -1791,12 +1799,13 @@ test_sm_state_map () tree y = build_global_decl ("y", integer_type_node); tree z = build_global_decl ("z", integer_type_node); - state_machine *sm = make_malloc_state_machine (NULL); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (sm); - engine eng; - extrinsic_state ext_state (checkers, &eng); + std::unique_ptr<state_machine> sm = make_malloc_state_machine (nullptr); state_machine::state_t start = sm->get_start_state (); + std::vector<std::unique_ptr<state_machine>> checkers; + const state_machine &borrowed_sm = *sm.get (); + checkers.push_back (std::move (sm)); + engine eng; + extrinsic_state ext_state (std::move (checkers), &eng); /* Test setting states on svalue_id instances directly. */ { @@ -1804,11 +1813,11 @@ test_sm_state_map () const state_machine::state_t TEST_STATE_42 = &test_state_42; region_model_manager mgr; region_model model (&mgr); - const svalue *x_sval = model.get_rvalue (x, NULL); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *x_sval = model.get_rvalue (x, nullptr); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); - sm_state_map map (*sm); + sm_state_map map (borrowed_sm); ASSERT_TRUE (map.is_empty_p ()); ASSERT_EQ (map.get_state (x_sval, ext_state), start); @@ -1833,16 +1842,16 @@ test_sm_state_map () { region_model_manager mgr; region_model model (&mgr); - const svalue *x_sval = model.get_rvalue (x, NULL); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *x_sval = model.get_rvalue (x, nullptr); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); - sm_state_map map (*sm); + sm_state_map map (borrowed_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); - model.add_constraint (x, EQ_EXPR, y, NULL); + model.add_constraint (x, EQ_EXPR, y, nullptr); /* Setting x to a state should also update y, as they are in the same equivalence class. */ @@ -1857,12 +1866,12 @@ test_sm_state_map () { region_model_manager mgr; region_model model (&mgr); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); - sm_state_map map0 (*sm); - sm_state_map map1 (*sm); - sm_state_map map2 (*sm); + sm_state_map map0 (borrowed_sm); + sm_state_map map1 (borrowed_sm); + sm_state_map map2 (borrowed_sm); ASSERT_EQ (map0.hash (), map1.hash ()); ASSERT_EQ (map0, map1); @@ -1883,26 +1892,26 @@ 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); - sm_state_map map1 (*sm); - sm_state_map map2 (*sm); + sm_state_map map0 (borrowed_sm); + sm_state_map map1 (borrowed_sm); + sm_state_map map2 (borrowed_sm); ASSERT_EQ (map0.hash (), map1.hash ()); ASSERT_EQ (map0, map1); region_model_manager mgr; region_model model (&mgr); - const svalue *x_sval = model.get_rvalue (x, NULL); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *x_sval = model.get_rvalue (x, nullptr); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); - map1.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state); - map1.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state); - map1.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state); + map1.impl_set_state (x_sval, TEST_STATE_2, nullptr, ext_state); + map1.impl_set_state (y_sval, TEST_STATE_3, nullptr, ext_state); + map1.impl_set_state (z_sval, TEST_STATE_2, nullptr, ext_state); - map2.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state); - map2.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state); - map2.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state); + map2.impl_set_state (z_sval, TEST_STATE_2, nullptr, ext_state); + map2.impl_set_state (y_sval, TEST_STATE_3, nullptr, ext_state); + map2.impl_set_state (x_sval, TEST_STATE_2, nullptr, ext_state); ASSERT_EQ (map1.hash (), map2.hash ()); ASSERT_EQ (map1, map2); @@ -1920,27 +1929,25 @@ test_program_state_1 () malloc sm-state, pointing to a region on the heap. */ tree p = build_global_decl ("p", ptr_type_node); - state_machine *sm = make_malloc_state_machine (NULL); + std::unique_ptr<state_machine> sm = make_malloc_state_machine (nullptr); const state_machine::state_t UNCHECKED_STATE = sm->get_state_by_name ("unchecked"); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (sm); engine eng; - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (std::move (sm), &eng); region_model_manager *mgr = eng.get_model_manager (); program_state s (ext_state); region_model *model = s.m_region_model; const svalue *size_in_bytes = mgr->get_or_create_unknown_svalue (size_type_node); const region *new_reg - = model->get_or_create_region_for_heap_alloc (size_in_bytes, NULL); + = model->get_or_create_region_for_heap_alloc (size_in_bytes, nullptr); const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); - model->set_value (model->get_lvalue (p, NULL), - ptr_sval, NULL); + model->set_value (model->get_lvalue (p, nullptr), + ptr_sval, nullptr); sm_state_map *smap = s.m_checker_states[0]; - smap->impl_set_state (ptr_sval, UNCHECKED_STATE, NULL, ext_state); + smap->impl_set_state (ptr_sval, UNCHECKED_STATE, nullptr, ext_state); ASSERT_EQ (smap->get_state (ptr_sval, ext_state), UNCHECKED_STATE); } @@ -1955,15 +1962,15 @@ test_program_state_2 () tree string_cst_ptr = build_string_literal (4, "foo"); - auto_delete_vec <state_machine> checkers; + std::vector<std::unique_ptr<state_machine>> checkers; engine eng; - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (std::move (checkers), &eng); program_state s (ext_state); region_model *model = s.m_region_model; - const region *p_reg = model->get_lvalue (p, NULL); - const svalue *str_sval = model->get_rvalue (string_cst_ptr, NULL); - model->set_value (p_reg, str_sval, NULL); + const region *p_reg = model->get_lvalue (p, nullptr); + const svalue *str_sval = model->get_rvalue (string_cst_ptr, nullptr); + model->set_value (p_reg, str_sval, nullptr); } /* Verify that program_states with identical sm-state can be merged, @@ -1979,9 +1986,8 @@ test_program_state_merging () engine eng; region_model_manager *mgr = eng.get_model_manager (); program_point point (program_point::origin (*mgr)); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (make_malloc_state_machine (NULL)); - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (make_malloc_state_machine (nullptr), + &eng); program_state s0 (ext_state); uncertainty_t uncertainty; @@ -1991,20 +1997,20 @@ test_program_state_merging () const svalue *size_in_bytes = mgr->get_or_create_unknown_svalue (size_type_node); const region *new_reg - = model0->get_or_create_region_for_heap_alloc (size_in_bytes, NULL); + = model0->get_or_create_region_for_heap_alloc (size_in_bytes, nullptr); const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); model0->set_value (model0->get_lvalue (p, &ctxt), ptr_sval, &ctxt); sm_state_map *smap = s0.m_checker_states[0]; const state_machine::state test_state ("test state", 0); const state_machine::state_t TEST_STATE = &test_state; - smap->impl_set_state (ptr_sval, TEST_STATE, NULL, ext_state); + smap->impl_set_state (ptr_sval, TEST_STATE, nullptr, ext_state); ASSERT_EQ (smap->get_state (ptr_sval, ext_state), TEST_STATE); model0->canonicalize (); /* Verify that canonicalization preserves sm-state. */ - ASSERT_EQ (smap->get_state (model0->get_rvalue (p, NULL), ext_state), + ASSERT_EQ (smap->get_state (model0->get_rvalue (p, nullptr), ext_state), TEST_STATE); /* Make a copy of the program_state. */ @@ -2021,7 +2027,7 @@ test_program_state_merging () /* Verify that the merged state has the sm-state for "p". */ region_model *merged_model = merged.m_region_model; sm_state_map *merged_smap = merged.m_checker_states[0]; - ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL), + ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, nullptr), ext_state), TEST_STATE); @@ -2030,7 +2036,7 @@ test_program_state_merging () merged.validate (ext_state); /* Verify that the merged state still has the sm-state for "p". */ - ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL), + ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, nullptr), ext_state), TEST_STATE); @@ -2047,9 +2053,7 @@ test_program_state_merging_2 () engine eng; region_model_manager *mgr = eng.get_model_manager (); program_point point (program_point::origin (*mgr)); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (make_signal_state_machine (NULL)); - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (make_signal_state_machine (nullptr), &eng); const state_machine::state test_state_0 ("test state 0", 0); const state_machine::state test_state_1 ("test state 1", 1); |