From 8f6fde24e7f2dbfb3b7935dfb6b9b05b47edc6b7 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 6 Mar 2019 19:15:25 -0500
Subject: [PATCH 075/217] FIXME: WIP on expanding call summaries

---
 gcc/analyzer/engine.cc                         | 71 +++++++++++++++++++++++---
 gcc/common.opt                                 |  4 ++
 gcc/testsuite/gcc.dg/analyzer/malloc-paths-6.c | 11 ++++
 3 files changed, 80 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/malloc-paths-6.c

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index e24e333..485bc60 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -555,12 +555,19 @@ public:
   {
     m_events.safe_push (event);
   }
+
+  void add_event_at (checker_event *event, int idx)
+  {
+    m_events.safe_insert (idx, event);
+  }
   
   void delete_event (int idx)
   {
+#if 1
     checker_event *event = m_events[idx];
     m_events.ordered_remove (idx);
     delete event;
+#endif
   }
 
   auto_delete_vec<checker_event> m_events;
@@ -684,8 +691,9 @@ class engine : public log_user
 {
 public:
   engine (const supergraph &sg, const state_machine &sm,
-	  logger *logger)
+	  logger *logger, int verbosity)
   : log_user (logger), m_sg (sg), m_sm (sm), m_per_node_data (),
+    m_verbosity (verbosity),
     m_candidate_diagnostics (),
     m_num_traverse_calls (0),
     m_num_cache_hits (0),
@@ -741,6 +749,7 @@ public:
 		     const backtrace &b, const path_state &ps);
 
   void emit_candidate_diagnostics ();
+  void expand_path (checker_path *path, tree var, state_machine::state_t state);
   void prune_path (checker_path *path, tree var, state_machine::state_t state);
   void maybe_emit (const candidate_diagnostic &cd);
 
@@ -753,6 +762,8 @@ public:
   // FIXME: should this be just a vec, instead (using the node indices)?
   hash_map <const supernode *, per_node_t *> m_per_node_data;
 
+  int m_verbosity;
+
   auto_delete_vec <candidate_diagnostic> m_candidate_diagnostics;
 
   int m_num_traverse_calls;
@@ -2001,6 +2012,51 @@ engine::emit_candidate_diagnostics ()
 /* FIXME.  */
 
 void
+engine::expand_path (checker_path *path, tree var, state_machine::state_t state)
+{
+  // FIXME:
+  // expand call summaries (recursively?)
+  int idx = 0;
+  while (idx < path->m_events.length ())
+    {
+      checker_event *base_event = path->m_events[idx];
+      if (base_event->m_kind == EK_CALL_SUMMARY)
+	{
+	  call_summary *summary_event = (call_summary *)base_event;
+
+	  /* TODO: are we interested in a state change within this function?
+	     If not, we can simply eliminate it.
+	     If we are interested, we want to find a path (ideally feasible)
+	     within it that makes the state change happen.  We can probably
+	     figure that out from the suffix summaries.  */
+
+	  /* Build path representing the inside of the function.  */
+	  checker_path child_path;
+	  child_path.add_event (new debug_event (summary_event->m_loc,
+						 summary_event->m_fndecl,
+						 summary_event->m_depth,
+						 "calling"));
+	  child_path.add_event (new debug_event (summary_event->m_loc,
+						 summary_event->m_fndecl,
+						 summary_event->m_depth,
+						 "returning"));
+
+	  /* Replace the summary with a clone of the events on the child_path.  */
+	  path->delete_event (idx);
+#if 1
+	  for (int j = 0; j < child_path.m_events.length (); j++)
+	    path->add_event_at (child_path.m_events[j]->clone (), idx + j);
+	  idx += child_path.m_events.length ();
+#endif
+	}
+      else
+	idx++;
+    }
+}
+
+/* FIXME.  */
+
+void
 engine::prune_path (checker_path *path, tree var, state_machine::state_t state)
 {
   // TODO
@@ -2016,7 +2072,8 @@ engine::prune_path (checker_path *path, tree var, state_machine::state_t state)
 	  gcc_unreachable ();
 
 	case EK_DEBUG:
-	  path->delete_event (idx);
+	  if (m_verbosity < 2)
+	    path->delete_event (idx);
 	  break;
 
 	case EK_STATE_CHANGE:
@@ -2030,7 +2087,8 @@ engine::prune_path (checker_path *path, tree var, state_machine::state_t state)
 	    if (state_change->m_var != var)
 	      {
 		//inform (base_event->m_loc, "would filter");
-		path->delete_event (idx);
+		if (m_verbosity < 1)
+		  path->delete_event (idx);
 	      }
 	  }
 	  break;
@@ -2043,7 +2101,7 @@ engine::prune_path (checker_path *path, tree var, state_machine::state_t state)
 		    idx, base_event->m_desc);
 #endif
 	    // TODO: for now, filter them all:
-	    if (1)
+	    if (m_verbosity < 2)
 	      path->delete_event (idx);
 
 	    /* TODO: is this edge significant to var?
@@ -2063,7 +2121,7 @@ engine::prune_path (checker_path *path, tree var, state_machine::state_t state)
 		    idx, base_event->m_desc);
 #endif
 	    // TODO: for now, filter them all:
-	    if (0)
+	    if (m_verbosity < 1)
 	      path->delete_event (idx);
 
 	    // TODO
@@ -2099,6 +2157,7 @@ engine::maybe_emit (const candidate_diagnostic &cd)
   checker_path path (cd.m_path);
 #endif
 
+  expand_path (&path, cd.m_var, cd.m_state);
   prune_path (&path, cd.m_var, cd.m_state);
 
   char *msg = print ("here (%qE is in state %qs)", cd.m_var,
@@ -2274,7 +2333,7 @@ run_one_checker (const supergraph &sg, const state_machine &sm, logger *logger)
 	}
     }
 
-  engine e (sg, sm, logger);
+  engine e (sg, sm, logger, analyzer_verbosity);
 
   cgraph_node *node;
   auto_vec<cgraph_node *> root_functions;
diff --git a/gcc/common.opt b/gcc/common.opt
index f2b04e0..e575efa 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1344,6 +1344,10 @@ Common Joined RejectNegative Var(common_deferred_options) Defer
 fdump-analyzer
 Common RejectNegative Var(flag_dump_analyzer)
 
+fanalyzer-verbosity=
+Common Joined UInteger Var(analyzer_verbosity) Init(0)
+FIXME
+
 fdump-final-insns
 Driver RejectNegative
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-6.c b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-6.c
new file mode 100644
index 0000000..fad6fbc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-6.c
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+
+void test (void *ptr)
+{
+  void *q;
+  q = ptr;
+  free (ptr);
+  free (q); /* { dg-warning "double-free of 'q'" } */
+  /* The above case requires us to handle equivalence classes in
+     state transitions.  */
+}
-- 
1.8.5.3

