analyzer: reimplement on_transition in terms of get_state/set_next_state
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 28 Aug 2020 11:07:18 +0000 (07:07 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 9 Sep 2020 20:58:13 +0000 (16:58 -0400)
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
gcc/analyzer/engine.cc
gcc/analyzer/sm.h

index 04c7d2ac4d3f08d9793202147e4947b3ab8785d5..6fd15c21962b43ea5ee58321b109332d64fb9643 100644 (file)
@@ -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<const gassign *> (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?
                      }
index 05121e34b37589c4898f419bd031fb95e40766b0..07b1b15d195e2026095a2ae8030bbb7a06acba91 100644 (file)
@@ -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,
index 769d2a46767a151f77fead87441d794b64353eed..c5071464994f009d5e5579186adf5393bd7e93d1 100644 (file)
@@ -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