From 8c828409a11ded874214c02d4e5fd554ab75f576 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 21 Apr 2020 18:02:21 -0400
Subject: [PATCH 068/179] FIXME: WIP on pointer arithmetic and on function
 pointers

---
 gcc/analyzer/analyzer.h       |   1 +
 gcc/analyzer/region-model2.cc | 170 ++++++++++++++++++++++++++--------
 gcc/analyzer/region-model2.h  |  36 ++++---
 3 files changed, 155 insertions(+), 52 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 5e4440fa9f4..2c65723f8c5 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -63,6 +63,7 @@ class svalue2;
   class initial_svalue2;
 class region2;
   class map_region2;
+  class function_region2;
   class symbolic_region2;
   class field_region2;
 class region_model2_manager;
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index b5da026ecaa..84a168756a8 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -2203,6 +2203,18 @@ code_region2::valid_key_p (tree key) const
   return TREE_CODE (key) == FUNCTION_DECL;
 }
 
+/* FIXME.  */
+
+void
+code_region2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    {
+    }
+  else
+    pp_string (pp, "code_region2()");
+}
+
 /* class function_region2 : public map_region2.  */
 
 /* Compare the fields of this function_region2 with OTHER, returning true
@@ -2216,6 +2228,23 @@ function_region2::compare_fields (const function_region2 &other) const
 }
 #endif
 
+/* FIXME.  */
+
+void
+function_region2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    {
+      dump_quoted_tree (pp, m_fndecl);
+    }
+  else
+    {
+      pp_string (pp, "function_region2(");
+      dump_quoted_tree (pp, m_fndecl);
+      pp_string (pp, ")");
+    }
+}
+
 /* Implementation of map_region2::valid_key_p vfunc for function_region2.  */
 
 bool
@@ -2227,9 +2256,13 @@ function_region2::valid_key_p (tree key) const
 /* class stack_region2 : public region2.  */
 
 void
-stack_region2::dump_to_pp (pretty_printer */*pp*/, bool /*simple*/) const
+stack_region2::dump_to_pp (pretty_printer *pp, bool simple) const
 {
-  gcc_unreachable ();
+  if (simple)
+    {
+    }
+  else
+    pp_string (pp, "stack_region2()");
 }
 
 /* Compare the fields of this stack_region2 with OTHER, returning true
@@ -2734,7 +2767,6 @@ symbolic_region2::dump_to_pp (pretty_printer *pp, bool simple) const
 {
   if (simple)
     {
-      pp_string (pp, "*");
       m_sval_ptr->dump_to_pp (pp, simple);
     }
   else
@@ -2869,6 +2901,8 @@ region_model2_manager::region_model2_manager ()
 : m_next_region_id (0),
   m_root_region (alloc_region_id ()),
   m_stack_region (alloc_region_id (), &m_root_region),
+  m_code_region (alloc_region_id (), &m_root_region),
+  m_fndecls_map (),
   m_globals_region (alloc_region_id (), &m_root_region),
   m_globals_map ()
 {
@@ -2895,6 +2929,9 @@ region_model2_manager::~region_model2_manager ()
     delete (*iter).second;
 
   /* Delete consolidated regions.  */
+  for (fndecls_map_t::iterator iter = m_fndecls_map.begin ();
+       iter != m_fndecls_map.end (); ++iter)
+    delete (*iter).second;
   for (globals_map_t::iterator iter = m_globals_map.begin ();
        iter != m_globals_map.end (); ++iter)
     delete (*iter).second;
@@ -2986,6 +3023,23 @@ region_model2_manager::get_or_create_binop (tree type, enum tree_code op,
 
 /* FIXME.  */
 
+function_region2 *
+region_model2_manager::get_region_for_fndecl (tree fndecl,
+					      region_model2_context */*ctxt*/)
+{
+  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
+
+  function_region2 **slot = m_fndecls_map.get (fndecl);
+  if (slot)
+    return *slot;
+  function_region2 *reg
+    = new function_region2 (alloc_region_id (), &m_code_region, fndecl);
+  m_fndecls_map.put (fndecl, reg);
+  return reg;
+}
+
+/* FIXME.  */
+
 decl_region2 *
 region_model2_manager::get_region_for_global (tree expr,
 					      region_model2_context */*ctxt*/)
@@ -3633,7 +3687,7 @@ region_model2::on_gassign (const supernode */*snode*/,
 	  gcc_unreachable (); // TODO
       }
       break;
-#if 0
+
     case POINTER_PLUS_EXPR:
       {
 	/* e.g. "_1 = a_10(D) + 12;" */
@@ -3642,6 +3696,12 @@ region_model2::on_gassign (const supernode */*snode*/,
 
 	svalue2 *ptr_sval = get_rvalue (ptr, ctxt);
 	svalue2 *offset_sval = get_rvalue (offset, ctxt);
+
+	svalue2 *sval_binop
+	      = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
+					    ptr_sval, offset_sval);
+	set_value (lhs_reg, sval_binop, ctxt);
+#if 0
 	region2 *element_reg
 	  = get_or_create_pointer_plus_expr (TREE_TYPE (TREE_TYPE (ptr)),
 					     ptr_sval, offset_sval,
@@ -3649,9 +3709,11 @@ region_model2::on_gassign (const supernode */*snode*/,
 	svalue2 *element_ptr_sval
 	  = get_or_create_ptr_svalue2 (TREE_TYPE (ptr), element_reg);
 	set_value (lhs_reg, element_ptr_sval, ctxt);
+#endif
       }
       break;
 
+#if 0
     case POINTER_DIFF_EXPR:
       {
 	/* e.g. "_1 = p_2(D) - q_3(D);".  */
@@ -3661,16 +3723,16 @@ region_model2::on_gassign (const supernode */*snode*/,
 	set_to_new_unknown_value (lhs_reg, TREE_TYPE (lhs), ctxt);
       }
       break;
+#endif
 
     case MEM_REF:
       {
-	region2 *rhs_reg = get_lvalue (rhs1, ctxt);
-	svalue2 *rhs_sval
-	  = get_region2 (rhs_reg)->get_value (*this, true, ctxt);
-	set_value (lhs_reg, rhs_sval, ctxt);
+	svalue2 *ptr_sval = get_rvalue (rhs1, ctxt);
+	region2 *star_ptr_reg = deref_rvalue (ptr_sval, ctxt);
+	svalue2 *val = get_store_value (star_ptr_reg);
+	set_value (lhs_reg, val, ctxt);
       }
       break;
-#endif
 
     /* Assignments of the form
 	set_value (lvalue (LHS), rvalue (EXPR))
@@ -3793,8 +3855,7 @@ bool
 region_model2::on_gcall (const supernode *snode,
 			 const gcall *call)
 {
-  // TODO
-  //gcc_unreachable ();
+  region_model2_context *ctxt = NULL; // FIXME
 
   /* Debugging/test support.  */
   if (is_special_named_call_p (call, "__analyzer_dump", 0))
@@ -3819,6 +3880,33 @@ region_model2::on_gcall (const supernode *snode,
       warning_at (call->location, 0, "%s", t.as_string ());
     }
 
+  if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
+    {
+      region2 *lhs_reg = NULL;
+      tree lhs_type = NULL_TREE;
+      if (tree lhs = gimple_call_lhs (call))
+	{
+	  lhs_reg = get_lvalue (lhs, ctxt);
+	  lhs_type = TREE_TYPE (lhs);
+	}
+
+      if (is_named_call_p (callee_fndecl, "malloc", call, 1))
+	{
+	  // TODO: capture size as a svalue2?
+	  gcc_unreachable ();
+#if 0
+	  region2 *new_reg = add_new_malloc_region2 ();
+	  if (lhs_reg)
+	    {
+	      svalue2 *ptr_sval
+		= get_or_create_ptr_svalue2 (lhs_type, new_reg);
+	      set_value (lhs_reg, ptr_sval, ctxt);
+	    }
+#endif
+	  return true;
+	}
+    }
+
   return true;
 }
 
@@ -4419,6 +4507,9 @@ region_model2::get_lvalue_1 (path_var pv,
       }
       break;
 
+    case FUNCTION_DECL:
+      return m_mgr->get_region_for_fndecl (expr, ctxt);
+
     case VAR_DECL:
       /* Handle globals.  */
       if (is_global_var (expr))
@@ -4602,6 +4693,19 @@ region_model2::get_rvalue_1 (path_var pv,
     case STRING_CST:
       return m_mgr->get_or_create_constant_svalue2 (pv.m_tree);
 
+    case POINTER_PLUS_EXPR:
+	{
+	  tree expr = pv.m_tree;
+	  tree ptr = TREE_OPERAND (expr, 0);
+	  tree offset = TREE_OPERAND (expr, 1);
+	  svalue2 *ptr_sval = get_rvalue (ptr, ctxt);
+	  svalue2 *offset_sval = get_rvalue (offset, ctxt);
+	  svalue2 *sval_binop
+	    = m_mgr->get_or_create_binop (TREE_TYPE (expr), POINTER_PLUS_EXPR,
+					  ptr_sval, offset_sval);
+	  return sval_binop;
+	}
+
     case COMPONENT_REF:
     case MEM_REF:
       {
@@ -4688,22 +4792,6 @@ region_model2::get_svalue2_for_fndecl (tree ptr_type, tree fndecl,
 }
 #endif
 
-/* Return a function_region2 * for FNDECL, creating it if necessary.  */
-#if 0
-function_region2 *
-region_model2_manager::get_region2_for_fndecl (tree fndecl,
-					       region_model2_context *ctxt)
-{
-  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
-
-  region2 *code_reg = get_root_region2 ()->ensure_code_region2 (this);
-  code_region2 *code = get_root_region2 ()->get_code_region2 (this);
-
-  return code->get_or_create (this, code_reg, fndecl, TREE_TYPE (fndecl),
-			      ctxt);
-}
-#endif
-
 /* Return an svalue2 *for a region_svalue2 for LABEL,
    creating the label_region2 if necessary.  */
 #if 0
@@ -6495,7 +6583,7 @@ region_model2::get_or_create_view (region2 *raw_reg, tree type,
 
 /* Attempt to get the fndecl used at CALL, if known, or NULL_TREE
    otherwise.  */
-#if 0
+
 tree
 region_model2::get_fndecl_for_call (const gcall *call,
 				    region_model2_context *ctxt)
@@ -6504,16 +6592,12 @@ region_model2::get_fndecl_for_call (const gcall *call,
   if (fn_ptr == NULL_TREE)
     return NULL_TREE;
   svalue2 *fn_ptr_sval = get_rvalue (fn_ptr, ctxt);
-  svalue2 *fn_ptr_sval = get_svalue2 (fn_ptr_sval);
   if (region_svalue2 *fn_ptr_ptr = fn_ptr_sval->dyn_cast_region_svalue2 ())
     {
-      region2 *fn_reg = fn_ptr_ptr->get_pointee ();
-      code_region2 *code = get_root_region2 ()->get_code_region2 (this);
-      if (code)
+      region2 *reg = fn_ptr_ptr->get_pointee ();
+      if (function_region2 *fn_reg = reg->dyn_cast_function_region2 ())
 	{
-	  tree fn_decl = code->get_tree_for_child_region2 (fn_reg);
-	  if (!fn_decl)
-	    return NULL_TREE;
+	  tree fn_decl = fn_reg->get_fndecl ();
 	  cgraph_node *node = cgraph_node::get (fn_decl);
 	  if (!node)
 	    return NULL_TREE;
@@ -6525,7 +6609,6 @@ region_model2::get_fndecl_for_call (const gcall *call,
 
   return NULL_TREE;
 }
-#endif
 
 /* struct model_merger.  */
 
@@ -8444,7 +8527,20 @@ test_mem_ref ()
 static void
 test_POINTER_PLUS_EXPR_then_MEM_REF ()
 {
-  // TODO: gimple dump
+  tree int_star = build_pointer_type (integer_type_node);
+  tree a = build_global_decl ("a", int_star);
+  tree offset_12 = build_int_cst (size_type_node, 12);
+  tree pointer_plus_expr = build2 (POINTER_PLUS_EXPR, int_star, a, offset_12);
+  tree offset_0 = build_int_cst (integer_type_node, 0);
+  tree mem_ref = build2 (MEM_REF, integer_type_node,
+			 pointer_plus_expr, offset_0);
+  region_model2_manager mgr;
+  region_model2 m (&mgr);
+  svalue2 *tmp_2 = m.get_rvalue (mem_ref, NULL);
+  region2 *tmp_5 = m.get_lvalue (mem_ref, NULL);
+
+  tree int_42 = build_int_cst (integer_type_node, 42);
+  m.set_value (mem_ref, int_42, NULL);
 }
 
 /* Run all of the selftests within this file.  */
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 8b7f45c6bdf..1b6442855e9 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -683,6 +683,8 @@ public:
   enum kind get_kind () const FINAL OVERRIDE { return SK_BINOP; }
 
   enum tree_code get_op () const { return m_op; }
+  svalue2 *get_arg0 () const { return m_arg0; }
+  svalue2 *get_arg1 () const { return m_arg1; }
 
 #if 0
   void dump_dot_to_pp (const region_model2 &model,
@@ -748,7 +750,7 @@ namespace ana {
      stack_region (RK_STACK)
      heap_region (RK_HEAP)
      root_region (RK_ROOT)
-     label_region (RK_FUNCTION)
+     label_region (RK_LABEL)
      symbolic_region (RK_SYMBOLIC)
      field_region2 (RK_FIELD)
      element_region2 (RK_ELEMENT).  */
@@ -801,6 +803,7 @@ public:
 
   virtual enum kind get_kind () const = 0;
   virtual map_region2 *dyn_cast_map_region2 () { return NULL; }
+  virtual function_region2 *dyn_cast_function_region2 () { return NULL; }
   virtual symbolic_region2 *dyn_cast_symbolic_region2 () { return NULL; }
   virtual const symbolic_region2 *dyn_cast_symbolic_region2 () const { return NULL; }
 
@@ -1100,9 +1103,7 @@ public:
   {}
 
   /* region2 vfuncs.  */
-#if 0
-  region2 *clone () const FINAL OVERRIDE;
-#endif
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   enum kind get_kind () const FINAL OVERRIDE { return RK_CODE; }
 
   /* map_region2 vfunc.  */
@@ -1133,20 +1134,18 @@ namespace ana {
 class function_region2 : public map_region2
 {
 public:
-  function_region2 (unsigned id, region2 *parent, tree type)
-  : map_region2 (id, parent, type)
+  function_region2 (unsigned id, region2 *parent, tree fndecl)
+  : map_region2 (id, parent, TREE_TYPE (fndecl)), m_fndecl (fndecl)
   {
-    gcc_assert (FUNC_OR_METHOD_TYPE_P (type));
+    gcc_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndecl)));
   }
-  function_region2 (const function_region2 &other)
-  : map_region2 (other)
-  {}
 
   /* region2 vfuncs.  */
-#if 0
-  region2 *clone () const FINAL OVERRIDE;
-#endif
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   enum kind get_kind () const FINAL OVERRIDE { return RK_FUNCTION; }
+  function_region2 *dyn_cast_function_region2 () { return this; }
+
+  tree get_fndecl () const { return m_fndecl; }
 
   /* map_region2 vfunc.  */
   bool valid_key_p (tree key) const FINAL OVERRIDE;
@@ -1156,6 +1155,9 @@ public:
 			region_model2_context *ctxt);
 
   bool compare_fields (const function_region2 &other) const;
+
+private:
+  tree m_fndecl;
 };
 
 } // namespace ana
@@ -1531,6 +1533,11 @@ private:
 
   /* region2 consolidation.  */
 
+  code_region2 m_code_region;
+  typedef hash_map<tree, function_region2 *> fndecls_map_t;
+  typedef fndecls_map_t::iterator fndecls_iterator_t;
+  fndecls_map_t m_fndecls_map;
+
   globals_region2 m_globals_region;
   typedef hash_map<tree, decl_region2 *> globals_map_t;
   typedef globals_map_t::iterator globals_iterator_t;
@@ -1746,10 +1753,9 @@ class region_model2
 					     region_model2_context *ctxt);
   region2_id get_or_create_view (region2_id raw_rid, tree type,
 				region_model2_context *ctxt);
-
+#endif
   tree get_fndecl_for_call (const gcall *call,
 			    region_model2_context *ctxt);
-#endif
 
  private:
   region2 *get_lvalue_1 (path_var pv,
-- 
2.21.0

