From 264ce9436f42ec862fd05a011fe7fd6d1ed202ec Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 1 Oct 2020 13:22:56 -0400
Subject: [PATCH 26/47] FIXME: get callbacks-3.c to work (PR analyzer/97258)

---
 gcc/analyzer/engine.cc                      | 43 +++++++++++++++++++++
 gcc/analyzer/exploded-graph.h               |  8 ++++
 gcc/analyzer/region-model-reachability.cc   |  9 ++++-
 gcc/analyzer/region-model-reachability.h    |  3 +-
 gcc/analyzer/region-model.cc                |  2 +-
 gcc/analyzer/region-model.h                 |  5 +++
 gcc/testsuite/gcc.dg/analyzer/callbacks-3.c |  2 +-
 7 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 692b56e120e..4392d189046 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -143,6 +143,12 @@ impl_region_model_context::on_unknown_change (const svalue *sval,
     smap->on_unknown_change (sval, is_mutable, m_ext_state);
 }
 
+void
+impl_region_model_context::on_escaped_function (tree fndecl)
+{
+  m_eg->on_escaped_function (fndecl);
+}
+
 /* class setjmp_svalue : public svalue.  */
 
 /* Implementation of svalue::accept vfunc for setjmp_svalue.  */
@@ -1984,6 +1990,15 @@ exploded_graph::~exploded_graph ()
 exploded_node *
 exploded_graph::add_function_entry (function *fun)
 {
+  /* Be idempotent.  */
+  if (m_functions_with_enodes.contains (fun))
+    {
+      logger * const logger = get_logger ();
+       if (logger)
+	logger->log ("entrypoint for %qE already exists", fun->decl);
+      return NULL;
+    }
+
   program_point point = program_point::from_function_entry (m_sg, fun);
   program_state state (m_ext_state);
   state.push_frame (m_ext_state, fun);
@@ -1995,6 +2010,9 @@ exploded_graph::add_function_entry (function *fun)
   /* We should never fail to add such a node.  */
   gcc_assert (enode);
   add_edge (m_origin, enode, NULL);
+
+  m_functions_with_enodes.add (fun);
+
   return enode;
 }
 
@@ -3991,6 +4009,31 @@ exploded_graph::get_node_by_index (int idx) const
   return enode;
 }
 
+/* FIXME.  */
+
+void
+exploded_graph::on_escaped_function (tree fndecl)
+{
+  logger * const logger = get_logger ();
+  LOG_FUNC (logger);
+
+  cgraph_node *cgnode = cgraph_node::get (fndecl);
+  if (!cgnode)
+    return;
+
+  function *fun = cgnode->get_fun ();
+
+  exploded_node *enode = add_function_entry (fun);
+  if (logger)
+    {
+      if (enode)
+	logger->log ("created EN %i for %qE entrypoint",
+		     enode->m_index, fun->decl);
+      else
+	logger->log ("did not create enode for %qE entrypoint", fun->decl);
+    }
+}
+
 /* A collection of classes for visualizing the callgraph in .dot form
    (as represented in the supergraph).  */
 
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index fadf22cbdd0..b07752756f8 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -66,6 +66,8 @@ class impl_region_model_context : public region_model_context
   void on_unexpected_tree_code (tree t,
 				const dump_location_t &loc) FINAL OVERRIDE;
 
+  void on_escaped_function (tree fndecl) FINAL OVERRIDE;
+
   exploded_graph *m_eg;
   log_user m_logger;
   const exploded_node *m_enode_for_diag;
@@ -800,6 +802,8 @@ public:
     return m_worklist.get_scc_id (node);
   }
 
+  void on_escaped_function (tree fndecl);
+
 private:
   void print_bar_charts (pretty_printer *pp) const;
 
@@ -846,6 +850,10 @@ private:
   call_string_data_map_t m_per_call_string_data;
 
   auto_vec<int> m_PK_AFTER_SUPERNODE_per_snode;
+
+  /* Functions with a top-level enode, to make add_function_entry
+     be idempotent, for use in handling callbacks.  */
+  hash_set<function *> m_functions_with_enodes;
 };
 
 /* A path within an exploded_graph: a sequence of edges.  */
diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc
index c1b3b2db630..239dbb58e42 100644
--- a/gcc/analyzer/region-model-reachability.cc
+++ b/gcc/analyzer/region-model-reachability.cc
@@ -208,15 +208,22 @@ reachable_regions::handle_parm (const svalue *sval, tree param_type)
 
 /* Update m_store to mark the clusters that were found to be mutable
    as having escaped.  */
+// TODO
 
 void
-reachable_regions::mark_escaped_clusters ()
+reachable_regions::mark_escaped_clusters (region_model_context *ctxt)
 {
+  gcc_assert (ctxt);
   for (hash_set<const region *>::iterator iter = m_mutable_base_regs.begin ();
        iter != m_mutable_base_regs.end (); ++iter)
     {
       const region *base_reg = *iter;
       m_store->mark_as_escaped (base_reg);
+
+      /* If we have a function that's escaped, potentially add
+	 it to the worklist.  */
+      if (const function_region *fn_reg = base_reg->dyn_cast_function_region ())
+	ctxt->on_escaped_function (fn_reg->get_fndecl ());
     }
 }
 
diff --git a/gcc/analyzer/region-model-reachability.h b/gcc/analyzer/region-model-reachability.h
index aba1a58ec7f..7d51c547676 100644
--- a/gcc/analyzer/region-model-reachability.h
+++ b/gcc/analyzer/region-model-reachability.h
@@ -60,7 +60,8 @@ public:
 
   /* Update the store to mark the clusters that were found to be mutable
      as having escaped.  */
-  void mark_escaped_clusters ();
+  // TODO
+  void mark_escaped_clusters (region_model_context *ctxt);
 
   /* Iteration over reachable base regions.  */
   hash_set<const region *>::iterator begin ()
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index a88a295a241..f35b8be0a9f 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -884,7 +884,7 @@ region_model::handle_unrecognized_call (const gcall *call,
     }
 
   /* Mark any clusters that have escaped.  */
-  reachable_regs.mark_escaped_clusters ();
+  reachable_regs.mark_escaped_clusters (ctxt);
 
   /* Update bindings for all clusters that have escaped, whether above,
      or previously.  */
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index cfeac8d6951..8bbec5e76cf 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -2792,6 +2792,9 @@ class region_model_context
      know how to handle the tree code of T at LOC.  */
   virtual void on_unexpected_tree_code (tree t,
 					const dump_location_t &loc) = 0;
+
+  // TODO
+  virtual void on_escaped_function (tree fndecl) = 0;
 };
 
 /* A "do nothing" subclass of region_model_context.  */
@@ -2818,6 +2821,8 @@ public:
   {
   }
   void on_unexpected_tree_code (tree, const dump_location_t &) OVERRIDE {}
+
+  void on_escaped_function (tree) OVERRIDE {}
 };
 
 /* A subclass of region_model_context for determining if operations fail
diff --git a/gcc/testsuite/gcc.dg/analyzer/callbacks-3.c b/gcc/testsuite/gcc.dg/analyzer/callbacks-3.c
index 3a9632aedc5..5f12c2a28d3 100644
--- a/gcc/testsuite/gcc.dg/analyzer/callbacks-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/callbacks-3.c
@@ -9,7 +9,7 @@ extern void qsort(void *__base, size_t __nmemb, size_t __size,
 static int
 test_1_callback (const void *p1, const void *p2)
 {
-  __analyzer_dump_path (); // TODO: should report here
+  __analyzer_dump_path (); /* { dg-message "here" } */
   return 0;
 }
 
-- 
2.26.2

