From 6d9ca8c8604e2e7c2403794baf691b260cc71fb9 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 28 Aug 2020 07:07:18 -0400 Subject: [PATCH] analyzer: reimplement on_transition in terms of get_state/set_next_state This patch is further preliminary work towards generalizing sm-malloc.cc beyond just malloc/free. Reimplement sm_context's on_transition vfunc in terms of new get_state and set_next_state vfuncs, so that in followup patches we can implement richer transitions (e.g. where the states are parametrized by allocator). gcc/analyzer/ChangeLog: * diagnostic-manager.cc (null_assignment_sm_context::null_assignment_sm_context): Add old_state and ext_state params, initializing m_old_state and m_ext_state. (null_assignment_sm_context::on_transition): Split into... (null_assignment_sm_context::get_state): ...this new vfunc implementation and... (null_assignment_sm_context::set_next_state): ...this new vfunc implementation. (null_assignment_sm_context::m_old_state): New field. (null_assignment_sm_context::m_ext_state): New field. (diagnostic_manager::add_events_for_eedge): Pass in old state and ext_state when creating sm_ctxt. * engine.cc (impl_sm_context::on_transition): Split into... (impl_sm_context::get_state): ...this new vfunc implementation and... (impl_sm_context::set_next_state): ...this new vfunc implementation. * sm.h (sm_context::get_state): New pure virtual function. (sm_context::set_next_state): Likewise. (sm_context::on_transition): Convert from a pure virtual function to a regular function implemented in terms of get_state and set_next_state. --- gcc/analyzer/diagnostic-manager.cc | 41 +++++++++++++++++++-------- gcc/analyzer/engine.cc | 45 +++++++++++++++++++----------- gcc/analyzer/sm.h | 27 ++++++++++++++---- 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 04c7d2ac4d3..6fd15c21962 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -754,12 +754,15 @@ struct null_assignment_sm_context : public sm_context { null_assignment_sm_context (int sm_idx, const state_machine &sm, + const program_state *old_state, const program_state *new_state, const gimple *stmt, const program_point *point, - checker_path *emission_path) - : sm_context (sm_idx, sm), m_new_state (new_state), - m_stmt (stmt), m_point (point), m_emission_path (emission_path) + checker_path *emission_path, + const extrinsic_state &ext_state) + : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state), + m_stmt (stmt), m_point (point), m_emission_path (emission_path), + m_ext_state (ext_state) { } @@ -768,13 +771,25 @@ struct null_assignment_sm_context : public sm_context return NULL_TREE; } - void on_transition (const supernode *node ATTRIBUTE_UNUSED, - const gimple *stmt ATTRIBUTE_UNUSED, - tree var, - state_machine::state_t from, - state_machine::state_t to, - tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE + state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED, + tree var) FINAL OVERRIDE { + const svalue *var_old_sval + = m_old_state->m_region_model->get_rvalue (var, NULL); + const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx]; + + state_machine::state_t current + = old_smap->get_state (var_old_sval, m_ext_state); + + return current; + } + + void set_next_state (const gimple *stmt, + tree var, + state_machine::state_t to, + tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE + { + state_machine::state_t from = get_state (stmt, var); if (from != m_sm.get_start_state ()) return; @@ -791,7 +806,6 @@ struct null_assignment_sm_context : public sm_context from, to, NULL, *m_new_state)); - } void warn_for_state (const supernode *, const gimple *, @@ -833,11 +847,13 @@ struct null_assignment_sm_context : public sm_context return NULL_TREE; } + const program_state *m_old_state; const program_state *m_new_state; const gimple *m_stmt; const program_point *m_point; state_change_visitor *m_visitor; checker_path *m_emission_path; + const extrinsic_state &m_ext_state; }; /* Subroutine of diagnostic_manager::build_emission_path. @@ -943,15 +959,18 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb, if (const gassign *assign = dyn_cast (stmt)) { const extrinsic_state &ext_state = pb.get_ext_state (); + program_state old_state (iter_state); iter_state.m_region_model->on_assignment (assign, NULL); for (unsigned i = 0; i < ext_state.get_num_checkers (); i++) { const state_machine &sm = ext_state.get_sm (i); null_assignment_sm_context sm_ctxt (i, sm, + &old_state, &iter_state, stmt, &iter_point, - emission_path); + emission_path, + pb.get_ext_state ()); sm.on_stmt (&sm_ctxt, dst_point.get_supernode (), stmt); // TODO: what about phi nodes? } diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 05121e34b37..07b1b15d195 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -205,12 +205,26 @@ public: return model->get_fndecl_for_call (call, &old_ctxt); } - void on_transition (const supernode *node ATTRIBUTE_UNUSED, - const gimple *stmt, - tree var, - state_machine::state_t from, - state_machine::state_t to, - tree origin) FINAL OVERRIDE + state_machine::state_t get_state (const gimple *stmt, + tree var) + { + logger * const logger = get_logger (); + LOG_FUNC (logger); + impl_region_model_context old_ctxt + (m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/, + stmt); + const svalue *var_old_sval + = m_old_state->m_region_model->get_rvalue (var, &old_ctxt); + + state_machine::state_t current + = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ()); + return current; + } + + void set_next_state (const gimple *stmt, + tree var, + state_machine::state_t to, + tree origin) { logger * const logger = get_logger (); LOG_FUNC (logger); @@ -230,17 +244,14 @@ public: state_machine::state_t current = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ()); - if (current == from) - { - if (logger) - logger->log ("%s: state transition of %qE: %s -> %s", - m_sm.get_name (), - var, - from->get_name (), - to->get_name ()); - m_new_smap->set_state (m_new_state->m_region_model, var_new_sval, - to, origin_new_sval, m_eg.get_ext_state ()); - } + if (logger) + logger->log ("%s: state transition of %qE: %s -> %s", + m_sm.get_name (), + var, + current->get_name (), + to->get_name ()); + m_new_smap->set_state (m_new_state->m_region_model, var_new_sval, + to, origin_new_sval, m_eg.get_ext_state ()); } void warn_for_state (const supernode *snode, const gimple *stmt, diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h index 769d2a46767..c5071464994 100644 --- a/gcc/analyzer/sm.h +++ b/gcc/analyzer/sm.h @@ -170,15 +170,32 @@ public: other callback handling. */ virtual tree get_fndecl_for_call (const gcall *call) = 0; + /* Get the old state of VAR at STMT. */ + virtual state_machine::state_t get_state (const gimple *stmt, + tree var) = 0; + /* Set the next state of VAR to be TO, recording the "origin" of the + state as ORIGIN. + Use STMT for location information. */ + virtual void set_next_state (const gimple *stmt, + tree var, + state_machine::state_t to, + tree origin = NULL_TREE) = 0; + /* Called by state_machine in response to pattern matches: if VAR is in state FROM, transition it to state TO, potentially recording the "origin" of the state as ORIGIN. Use NODE and STMT for location information. */ - virtual void on_transition (const supernode *node, const gimple *stmt, - tree var, - state_machine::state_t from, - state_machine::state_t to, - tree origin = NULL_TREE) = 0; + void on_transition (const supernode *node ATTRIBUTE_UNUSED, + const gimple *stmt, + tree var, + state_machine::state_t from, + state_machine::state_t to, + tree origin = NULL_TREE) + { + state_machine::state_t current = get_state (stmt, var); + if (current == from) + set_next_state (stmt, var, to, origin); + } /* Called by state_machine in response to pattern matches: issue a diagnostic D if VAR is in state STATE, using NODE and STMT -- 2.30.2