From 9bd57c71a3e6f9632515c88f813d31fdd5105e3e Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 27 Apr 2020 16:27:35 -0400
Subject: [PATCH 079/193] FIXME: treat regions pointer to by initial values of
 pointer parms as escaped

---
 gcc/analyzer/region-model2.cc                 | 42 +++++++++++++++++--
 gcc/analyzer/region-model2.h                  |  1 +
 gcc/analyzer/store2.cc                        |  7 +++-
 gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c | 30 +++++++++++++
 4 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index f3d406d0788..f1a5f82ec2d 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -6266,6 +6266,27 @@ region_model2::get_stack_region2 *() const
 }
 #endif
 
+/* For use with push_frame when handling a top-level call within the analysis.
+   PARAM has a defined but unknown initial value.
+   Anything it points to has escaped, since the calling context "knows"
+   the pointer, and thus calls to unknown functions could read/write into
+   the region.  */
+
+void
+region_model2::on_top_level_param (tree param,
+				   region_model2_context *ctxt)
+{
+  if (POINTER_TYPE_P (TREE_TYPE (param)))
+    {
+      region2 *param_reg = get_lvalue (param, ctxt);
+      svalue2 *init_ptr_sval
+	= m_mgr->get_or_create_initial_value (param_reg);
+      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);
+    }
+}
+
 // FIXME:
 /* Create a new frame_region2 for a call to FUN and push it onto
    the stack.
@@ -6278,7 +6299,7 @@ region_model2::get_stack_region2 *() const
 
 region2 *
 region_model2::push_frame (function *fun, vec<svalue2 *> *arg_svals,
-			   region_model2_context */*ctxt*/)
+			   region_model2_context *ctxt)
 {
   m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
   if (arg_svals)
@@ -6315,8 +6336,23 @@ region_model2::push_frame (function *fun, vec<svalue2 *> *arg_svals,
 #endif
 	}
     }
-  /* Otherwise we have a top-level call within the analysis.  The params
-     have defined but unknown initial values.  */
+  else
+    {
+      /* Otherwise we have a top-level call within the analysis.  The params
+	 have defined but unknown initial values.
+	 Anything they point to has escaped.  */
+      tree fndecl = fun->decl;
+      for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
+	   iter_parm = DECL_CHAIN (iter_parm))
+	{
+	  on_top_level_param (iter_parm, ctxt);
+	  /* TODO: also do it for default SSA name (sharing the same unknown
+	     value).  */
+	  tree parm_default_ssa = ssa_default_def (fun, iter_parm);
+	  if (parm_default_ssa)
+	    on_top_level_param (parm_default_ssa, ctxt);
+	}
+    }
 
   return m_current_frame;
 }
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 05e550cdb39..e4fc3395cf9 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -1942,6 +1942,7 @@ class region_model2
 				      auto_vec<path_var> *rep_path_vars,
 				      bool *is_first);
 #endif
+  void on_top_level_param (tree param, region_model2_context *ctxt);
 
   void record_dynamic_extents (region2 *reg, svalue2 *size_in_bytes);
 
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index b6b51fe8898..807df24becf 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -568,7 +568,12 @@ store2::on_escape_to_unknown_fncall (store2_manager *mgr,
 
   if (binding_cluster2 **cluster_slot = m_cluster_map.get (base_reg))
     (*cluster_slot)->on_escape_to_unknown_fncall (mgr);
-  // TODO
+  else
+    {
+      binding_cluster2 *cluster = new binding_cluster2 ();
+      m_cluster_map.put (base_reg, cluster);
+      cluster->on_escape_to_unknown_fncall (mgr);
+    }
   /* FIXME: but don't bother marking every global as escaped; instead,
      clear these.  */
 }
diff --git a/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c b/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c
index 42d6009d4db..fd99127e3ec 100644
--- a/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c
@@ -89,3 +89,33 @@ void test_3 (void)
   unknown_fn (NULL);
   __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
 }
+
+struct used_by_test_4
+{
+  int *int_ptr;
+};
+
+void test_4 (struct used_by_test_4 *st4_ptr)
+{
+  /* Something unknown called "test_4", and hence *st4_ptr has
+     effectively already escaped.  */
+
+  int i = 42;
+  __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
+
+  unknown_fn (NULL);
+  __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
+
+  /* Given that *st4_ptr has effectively already escaped, calling
+     an unknown fn should invalidate our knowledge of i".  */
+  st4_ptr->int_ptr = &i;
+  unknown_fn (NULL);
+  __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */
+
+  /* ...and "&i" should now be treated as having escaped.  */
+  i = 17;
+  __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
+  st4_ptr->int_ptr = NULL;
+  unknown_fn (NULL);
+  __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
+}
-- 
2.21.0

