From 6619531c461fa9ca9197318990ea7007de80fcaf Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 8 Mar 2019 13:13:31 -0500
Subject: [PATCH 085/161] FIXME: track origins of state changes and use them
 when filtering

---
 gcc/analyzer/engine.cc                  | 67 ++++++++++++++++++++++-----------
 gcc/analyzer/hardcoded-state-machine.h  |  3 +-
 gcc/testsuite/gcc.dg/analyzer/taint-1.c |  8 +++-
 3 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 70e5256..7337d79 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -497,30 +497,39 @@ public:
 		      const state_machine &sm,
 		      tree var,
 		      state_machine::state_t from,
-		      state_machine::state_t to)
+		      state_machine::state_t to,
+		      tree origin)
   : checker_event (EK_STATE_CHANGE,
 		   stmt->location, node->m_fun->decl,
 		   stack_depth,
-		   make_desc (var, sm, from, to)),
+		   make_desc (var, sm, from, to, origin)),
     m_node (node), m_stmt (stmt), m_sm (sm),
-    m_var (var), m_from (from), m_to (to)
+    m_var (var), m_from (from), m_to (to),
+    m_origin (origin)
   {
   }
 
   static char *make_desc (tree var,
 			  const state_machine &sm,
 			  state_machine::state_t from,
-			  state_machine::state_t to)
-  {
-    return print ("state of %qE: %qs -> %qs", var,
-		  sm.get_state_name (from),
-		  sm.get_state_name (to));
+			  state_machine::state_t to,
+			  tree origin)
+  {
+    if (origin)
+      return print ("state of %qE: %qs -> %qs (origin: %qE)", var,
+		    sm.get_state_name (from),
+		    sm.get_state_name (to),
+		    origin);
+    else
+      return print ("state of %qE: %qs -> %qs (origin: NULL)", var,
+		    sm.get_state_name (from),
+		    sm.get_state_name (to));
   }
 
   checker_event *clone () const FINAL OVERRIDE
   {
     return new state_change_event (m_node, m_stmt, m_depth,
-				   m_sm, m_var, m_from, m_to);
+				   m_sm, m_var, m_from, m_to, m_origin);
   }
 
   const supernode *m_node;
@@ -529,6 +538,7 @@ public:
   tree m_var;
   state_machine::state_t m_from;
   state_machine::state_t m_to;
+  tree m_origin;
 };
 
 class edge_event : public checker_event
@@ -1046,7 +1056,8 @@ public:
   void on_transition (const supernode *node, const gimple *stmt,
 		      tree var,
 		      state_machine::state_t from,
-		      state_machine::state_t to) FINAL OVERRIDE
+		      state_machine::state_t to,
+		      tree origin) FINAL OVERRIDE
   {
     JIT_LOG_FUNC_2 (m_engine->get_logger (),
 		    "from: %s to: %s",
@@ -1096,15 +1107,21 @@ public:
 	      continue;
 	  }
 
-	m_sm_inst->m_active_vars.m_set.add (var_state_t (ec_var->m_tree, to));
+	var_state_t new_vs (ec_var->m_tree, to);
+	m_sm_inst->m_active_vars.m_set.add (new_vs);
+	if (m_engine->get_logger ())
+	  m_engine->log ("adding active var: %s",
+			 new_vs.to_str (m_engine->m_sm).c_str ());
 
 	if (m_path)
 	  {
 	    checker_event *event
 	      = new state_change_event (node, stmt, m_path->m_stack_depth,
 					m_engine->m_sm,
-					var, from, to);
+					ec_var->m_tree, from, to, origin);
 	    m_path->add_event (event);
+	    if (m_engine->get_logger ())
+	      m_engine->log ("adding event: %s", event->to_str ().c_str ());
 	  }
 
 	per_stmt_t &stmt_data = m_engine->get_data_for_stmt (stmt);
@@ -1522,10 +1539,11 @@ engine::on_stmt (const supernode *node, const gimple *stmt,
 		  {
 		    log ("got match for COMPONENT_REF");
 		    engine_sm_context ctxt (this, b, sm_inst, old_sm_inst,
-					    NULL /* FIXME */, ps);
+					    path, ps);
 		    // FIXME: we want to overwrite any old states
 		    // (but respect the gstate, I think):
-		    ctxt.on_transition (node, stmt, lhs, 0/* FIXME */, (*iter).m_state);
+		    ctxt.on_transition (node, stmt, lhs, 0/* FIXME */,
+					(*iter).m_state, (*iter).m_var);
 		  }
 	      }
 	  }
@@ -1621,7 +1639,8 @@ engine::on_assignment (const supernode *node, const gimple *stmt,
 				  NULL /* FIXME */, ps);
 	  // FIXME: we want to overwrite any old states
 	  // (but respect the gstate, I think):
-	  ctxt.on_transition (node, stmt, lhs, 0/* FIXME */, (*iter).m_state);
+	  ctxt.on_transition (node, stmt, lhs, 0/* FIXME */, (*iter).m_state,
+			      rhs);
 	}
     }
 
@@ -1837,7 +1856,7 @@ engine::restore_after_call (sm_instance sm_inst_in_callee, cgraph_edge *edge,
 	      // (but respect the gstate, I think):
 	      ctxt.on_transition (rest_of_caller_node, call_stmt, arg,
 				  0/* FIXME */,
-				  (*iter).m_state);
+				  (*iter).m_state, parm);
 	    }
 	}
     }
@@ -2270,7 +2289,8 @@ engine::expand_call_summary (const call_summary *summary_event,
 						m_sm,
 						e.m_start.m_varstate.m_var,
 						e.m_start.m_varstate.m_state,
-						e.m_end.m_varstate.m_state);
+						e.m_end.m_varstate.m_state,
+						NULL_TREE /* FIXME: origin */);
 		    result->add_event (event);
 		  }
 
@@ -2421,14 +2441,19 @@ engine::prune_path (checker_path *path, tree var, state_machine::state_t state)
 	case EK_STATE_CHANGE:
 	  {
 	    state_change_event *state_change = (state_change_event *)base_event;
-	    if (state_change->m_var != var)
+	    if (state_change->m_var == var)
 	      {
-		if (m_verbosity < 2)
+		if (state_change->m_origin)
 		  {
-		    log ("filtering event %i: unrelated state change", idx);
-		    path->delete_event (idx);
+		    log ("event %i: switching to origin", idx); // FIXME: show %qE
+		    var = state_change->m_origin;
 		  }
 	      }
+	    else if (m_verbosity < 2)
+	      {
+		log ("filtering event %i: unrelated state change", idx);
+		path->delete_event (idx);
+	      }
 	  }
 	  break;
 
diff --git a/gcc/analyzer/hardcoded-state-machine.h b/gcc/analyzer/hardcoded-state-machine.h
index 25bb697..cbc30de 100644
--- a/gcc/analyzer/hardcoded-state-machine.h
+++ b/gcc/analyzer/hardcoded-state-machine.h
@@ -99,7 +99,8 @@ public:
   virtual void on_transition (const supernode *node, const gimple *stmt,
 			      tree var,
 			      state_machine::state_t from,
-			      state_machine::state_t to) = 0;
+			      state_machine::state_t to,
+			      tree origin = NULL_TREE) = 0;
 
   // Stuff used by impl 2:
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/taint-1.c b/gcc/testsuite/gcc.dg/analyzer/taint-1.c
index a18a11d..08ff892 100644
--- a/gcc/testsuite/gcc.dg/analyzer/taint-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/taint-1.c
@@ -12,11 +12,15 @@ char test_1(FILE *f)
 {
   struct foo tmp;
 
-  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
+  if (1 == fread(&tmp, sizeof(tmp), 1, f)) { /* { dg-message "\\(1\\) state of 'tmp': 'start' -> 'tainted'" } */
     /* BUG: the following array lookup trusts that the input data's index is
        in the range 0 <= i < 256; otherwise it's accessing the stack */
-    return tmp.buf[tmp.i]; // { dg-warning "use of tainted value '<unknown>' in array lookup without bounds checking" }
+    return tmp.buf[tmp.i]; // { dg-warning "use of tainted value '<unknown>' in array lookup without bounds checking" } */
+    /* { dg-message "23: \\(2\\) state of '<unknown>': 'start' -> 'tainted'" "" { target *-*-* } .-1 } */
+    /* { dg-message "\\(3\\) here \\('<unknown>' is in state 'tainted'\\)" "" { target *-*-* } .-2 } */
+    
     // TODO: better description of value
+    // TOOD: better messages for state changes
   }
   return 0;
 }
-- 
1.8.5.3

