From c7cc58e87775ac6b4733f25b88f954463d567531 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 21 Jul 2020 17:30:28 -0400
Subject: [PATCH 315/377] FIXME: rework null_assignment_sm_context to work on
 every stmt in enode, not just first

---
 gcc/analyzer/diagnostic-manager.cc       | 58 ++++++++++++++----------
 gcc/analyzer/program-point.cc            | 13 ++++++
 gcc/analyzer/program-point.h             |  8 +++-
 gcc/testsuite/gcc.dg/analyzer/malloc-1.c | 13 ++++++
 4 files changed, 67 insertions(+), 25 deletions(-)

diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 28924d493dd..dadbfc1aaf5 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -1035,12 +1035,11 @@ 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_old_state (old_state), m_new_state (new_state),
+  : sm_context (sm_idx, sm), m_new_state (new_state),
     m_stmt (stmt), m_point (point), m_emission_path (emission_path)
   {
   }
@@ -1060,8 +1059,6 @@ struct null_assignment_sm_context : public sm_context
     if (from != 0)
       return;
 
-    const svalue2 *var_old_sval
-      = m_old_state->m_region_model2->get_rvalue (var, NULL);
     const svalue2 *var_new_sval
       = m_new_state->m_region_model2->get_rvalue (var, NULL);
     const supernode *supernode = m_point->get_supernode ();
@@ -1117,7 +1114,6 @@ struct null_assignment_sm_context : public sm_context
     return NULL_TREE;
   }
 
-  const program_state *m_old_state;
   const program_state *m_new_state;
   const program_point *m_point;
   state_change_visitor2 *m_visitor;
@@ -1224,25 +1220,39 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
 				  dst_point.get_fndecl (),
 				  dst_stack_depth, dst_state));
 
-	/* Create state change events for assignment to NULL.  */
-	if (stmt->code == GIMPLE_ASSIGN)
-	  {
-	    const extrinsic_state &ext_state = pb.get_ext_state ();
-	    for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
-	      {
-		const state_machine &sm = ext_state.get_sm (i);
-		program_state state_after_stmt (dst_state);
-		state_after_stmt.m_region_model2->on_stmt (stmt, NULL);
-		null_assignment_sm_context sm_ctxt (i, sm,
-						    &dst_state,
-						    &state_after_stmt,
-						    stmt,
-						    &dst_point, emission_path);
-		sm.on_stmt (&sm_ctxt, dst_point.get_supernode (), stmt);
-		// TODO: what if it isn't the first stmt in the enode?
-		// TODO: what about phi nodes?
-	      }
-	  }
+	/* Create state change events for assignment to NULL.
+	   Iterate through the stmts in dst_enode, adding state change
+	   events for them.  */
+	{
+	  program_state iter_state (dst_state);
+	  program_point iter_point (dst_point);
+	  while (1)
+	    {
+	      const gimple *stmt = iter_point.get_stmt ();
+	      if (stmt->code == GIMPLE_ASSIGN)
+		{
+		  const extrinsic_state &ext_state = pb.get_ext_state ();
+		  iter_state.m_region_model2->on_stmt (stmt, 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,
+							  &iter_state,
+							  stmt,
+							  &iter_point,
+							  emission_path);
+		      sm.on_stmt (&sm_ctxt, dst_point.get_supernode (), stmt);
+		      // TODO: what about phi nodes?
+		    }
+		}
+	      iter_point.next_stmt ();
+	      if (iter_point.get_kind () == PK_AFTER_SUPERNODE
+		  || (dst_node->m_succs.length () > 1
+		      && (iter_point
+			  == dst_node->m_succs[0]->m_dest->get_point ())))
+		    break;
+	    }
+	}
       }
       break;
     }
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index a07f236fd71..e4893424f4d 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -538,6 +538,19 @@ function_point::cmp_within_supernode (const function_point &point_a,
   return result;
 }
 
+/* For PK_BEFORE_STMT, go to next stmt (or to PK_AFTER_SUPERNODE).  */
+
+void
+function_point::next_stmt ()
+{
+  gcc_assert (m_kind == PK_BEFORE_STMT);
+  if (++m_stmt_idx == m_supernode->m_stmts.length ())
+    {
+      m_kind = PK_AFTER_SUPERNODE;
+      m_stmt_idx = 0;
+    }
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h
index 8a9fd019260..23e8a0b91b0 100644
--- a/gcc/analyzer/program-point.h
+++ b/gcc/analyzer/program-point.h
@@ -146,6 +146,9 @@ public:
   static int cmp_within_supernode (const function_point &point_a,
 				   const function_point &point_b);
 
+  /* For before_stmt, go to next stmt.  */
+  void next_stmt ();
+
  private:
   const supernode *m_supernode;
 
@@ -292,8 +295,11 @@ public:
 
   void validate () const;
 
+  /* For before_stmt, go to next stmt.  */
+  void next_stmt () { m_function_point.next_stmt (); }
+
  private:
-  const function_point m_function_point;
+  function_point m_function_point;
   call_string m_call_string;
 };
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
index 27491428cd6..48766238d8b 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
@@ -586,3 +586,16 @@ void test_48 (void)
   int *p = NULL; /* { dg-message "'p' is NULL" } */
   *p = 1; /* { dg-warning "dereference of NULL 'p'" } */
 }
+
+/* As test_48, but where the assignment of NULL is not at the start of a BB.  */
+
+int test_49 (int i)
+{
+  int *p;
+  int x;
+
+  x = i * 2;
+  p = NULL; /* { dg-message "'p' is NULL" } */
+  *p = 1; /* { dg-warning "dereference of NULL 'p'" } */
+  return x;
+}
-- 
2.26.2

