From b72bb2be79ac4bd04e2a86da2dfd14d275a69668 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 2 Jul 2020 12:00:46 -0400
Subject: [PATCH 277/315] FIXME: fix unknown-fns.c:test_1 by separating marking
 of escaped clusters from updating on unknown fncall

---
 gcc/analyzer/region-model2-reachability.cc | 12 +++--
 gcc/analyzer/region-model2-reachability.h  |  5 +-
 gcc/analyzer/region-model2.cc              | 10 ++--
 gcc/analyzer/store2.cc                     | 54 ++++++++++++++++------
 gcc/analyzer/store2.h                      | 11 +++--
 5 files changed, 62 insertions(+), 30 deletions(-)

diff --git a/gcc/analyzer/region-model2-reachability.cc b/gcc/analyzer/region-model2-reachability.cc
index 644e330a396..1319ccafbca 100644
--- a/gcc/analyzer/region-model2-reachability.cc
+++ b/gcc/analyzer/region-model2-reachability.cc
@@ -201,20 +201,22 @@ reachable_region2s::handle_parm (const svalue2 *sval, tree param_type)
     }
 }
 
-/* Update m_store to set the clusters that were found to be mutable
-   to "unknown" values.  */
+/* Update m_store to mark the clusters that were found to be mutable
+   as having escaped.  */
 
 void
-reachable_region2s::update_bindings (store2_manager *mgr)
+reachable_region2s::mark_escaped_clusters (store2_manager *mgr)
 {
   for (hash_set<const region2 *>::iterator iter = m_mutable_regs.begin ();
        iter != m_mutable_regs.end (); ++iter)
     {
       const region2 *base_reg = *iter;
-      m_store->on_escape_to_unknown_fncall (mgr, base_reg);
+      m_store->mark_as_escaped (base_reg);
     }
 }
 
+/* Dump a multiline representation of this object to PP.  */
+
 void
 reachable_region2s::dump_to_pp (pretty_printer *pp) const
 {
@@ -256,6 +258,8 @@ reachable_region2s::dump_to_pp (pretty_printer *pp) const
     }
 }
 
+/* Dump a multiline representation of this object to stderr.  */
+
 DEBUG_FUNCTION void
 reachable_region2s::dump () const
 {
diff --git a/gcc/analyzer/region-model2-reachability.h b/gcc/analyzer/region-model2-reachability.h
index bec29216ae9..62acded445f 100644
--- a/gcc/analyzer/region-model2-reachability.h
+++ b/gcc/analyzer/region-model2-reachability.h
@@ -54,10 +54,9 @@ public:
      Use PARAM_TYPE for determining mutability.  */
   void handle_parm (const svalue2 *sval, tree param_type);
 
-  /* Update m_store to set the clusters that were found to be mutable
-     to "unknown" values.  */
+  /* FIXME.  */
 
-  void update_bindings (store2_manager *mgr);
+  void mark_escaped_clusters (store2_manager *mgr);
 
   /* Iteration over reachable regions.  */
   hash_set<const region2 *>::iterator begin ()
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 0fdab11b962..101cac7db21 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -5122,7 +5122,12 @@ region_model2::handle_unrecognized_call (const gcall *call,
       ctxt->on_unknown_change (sval, true);
     }
 
-  reachable_regs.update_bindings (m_mgr->get_store2_manager ());
+  /* Mark any clusters that have escaped.  */
+  reachable_regs.mark_escaped_clusters (m_mgr->get_store2_manager ());
+
+  /* Update bindings for all clusters that have escaped, whether above,
+     or previously.  */
+  m_store.on_unknown_fncall ();
 
 #if 0
   /* Purge sm-state for any remaining svalue2s that point to region2s that
@@ -7058,8 +7063,7 @@ region_model2::on_top_level_param (tree param,
       const svalue2 *init_ptr_sval
 	= m_mgr->get_or_create_initial_value (param_reg);
       const region2 *pointee_reg = m_mgr->get_symbolic_region (init_ptr_sval);
-      m_store.on_escape_to_unknown_fncall (m_mgr->get_store2_manager (),
-					   pointee_reg);
+      m_store.mark_as_escaped (pointee_reg);
     }
 }
 
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index 6d916664b01..75128e4bdc8 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -853,15 +853,11 @@ binding_cluster2::make_unknown_relative_to (const binding_cluster2 *other,
     }
 }
 
-/* FIXME.  */
+/* Mark this cluster as having escaped.  */
 
 void
-binding_cluster2::on_escape_to_unknown_fncall (store2_manager *mgr)
+binding_cluster2::mark_as_escaped ()
 {
-  m_map.empty ();
-  // TODO: need to add an "unknown" default value
-
-  /* Mark this cluster as having escaped.  */
   /* TODO: but maybe not if it's a global?
      they have automatically escaped already, and we want to be able
      to remove the cluster from the store if possible.
@@ -871,6 +867,23 @@ binding_cluster2::on_escape_to_unknown_fncall (store2_manager *mgr)
   m_escaped = true;
 }
 
+/* If this cluster has escaped (by this call, or by an earlier one, or
+   by being an external param), then unbind all values and mark it
+   as "touched", so that it has an unknown value, rather than an
+   initial_svalue2.  */
+
+void
+binding_cluster2::on_unknown_fncall ()
+{
+  if (m_escaped)
+    {
+      m_map.empty ();
+      // TODO: need to add an "unknown" default value
+
+      m_touched = true;
+    }
+}
+
 /* Return true if this binding_cluster2 has no information
    i.e. if there are no bindings, and it hasn't been marked as having
    escaped, or touched symbolically.  */
@@ -1569,26 +1582,37 @@ store2::can_merge_p (const store2 *store_a, const store2 *store_b,
   return true;
 }
 
-/* FIXME.
-   For use when handling an unrecognized function call.  */
-/* FIXME: do we want to mark the cluster as having escaped?
-   Further function calls could touch it, even if the cluster
+/* Mark the cluster for BASE_REG as having escaped.
+   For use when handling an unrecognized function call, and
+   for params to "top-level" calls.
+   Further unknown function calls could touch it, even if the cluster
    isn't reachable from args of those calls.  */
 
 void
-store2::on_escape_to_unknown_fncall (store2_manager *mgr,
-				     const region2 *base_reg)
+store2::mark_as_escaped (const region2 *base_reg)
 {
   gcc_assert (base_reg);
   gcc_assert (base_reg->get_base_region () == base_reg);
 
   binding_cluster2 *cluster = get_or_create_cluster (base_reg);
-  cluster->on_escape_to_unknown_fncall (mgr);
+  cluster->mark_as_escaped ();
   /* FIXME: but don't bother marking every global as escaped; instead,
-     clear these.  */
+     clear these on unknown fncalls.  */
 }
 
-/* FIXME.  */
+/* Handle an unknown fncall by updating any clusters that have escaped
+   (either in this fncall, or in a prior one).  */
+
+void
+store2::on_unknown_fncall ()
+{
+  for (cluster_map_t::iterator iter = m_cluster_map.begin ();
+       iter != m_cluster_map.end (); ++iter)
+    (*iter).second->on_unknown_fncall ();
+}
+
+/* Return true if a non-const pointer to BASE_REG (or something within it)
+   has escaped to code outside of the TU being analyzed.  */
 
 bool
 store2::escaped_p (const region2 *base_reg) const
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index ce1490b78bb..f1dcb6cc74a 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -385,7 +385,8 @@ public:
   void make_unknown_relative_to (const binding_cluster2 *other_cluster,
 				 store2_manager *mgr);
 
-  void on_escape_to_unknown_fncall (store2_manager *mgr);
+  void mark_as_escaped ();
+  void on_unknown_fncall ();
 
   bool escaped_p () const { return m_escaped; }
   bool touched_p () const { return m_touched; }
@@ -424,7 +425,8 @@ private:
   binding_map m_map;
 
   /* Has a pointer to this cluster "escaped" into a part of the program
-     we don't know about (via a call to a function with an unknown body).
+     we don't know about (via a call to a function with an unknown body,
+     or by being passed in as a pointer param of a "top-level" function call).
      Such regions could be overwritten when other such functions are called,
      even if the region is no longer reachable by pointers that we are
      tracking. */
@@ -496,9 +498,8 @@ public:
 			   store2 *out_store, store2_manager *mgr,
 			   model2_merger *merger);
 
-  void on_escape_to_unknown_fncall (store2_manager *mgr,
-				    const region2 *base_reg);
-
+  void mark_as_escaped (const region2 *base_reg);
+  void on_unknown_fncall ();
   bool escaped_p (const region2 *reg) const;
 
   void get_representative_path_vars (const region_model2 *model,
-- 
2.26.2

