From d56191aa82a0f0883995393ce53cba7e67b3fbce Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 22 Apr 2020 21:28:25 -0400
Subject: [PATCH 072/237] FIXME: add string_region2

---
 gcc/analyzer/analyzer.h       |  1 +
 gcc/analyzer/region-model2.cc | 79 ++++++++++++++++++++++++++++++-----
 gcc/analyzer/region-model2.h  | 39 ++++++++++++++++-
 3 files changed, 106 insertions(+), 13 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 2c65723f8c5..bc4bdbd355f 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -66,6 +66,7 @@ class region2;
   class function_region2;
   class symbolic_region2;
   class field_region2;
+  class string_region2;
 class region_model2_manager;
 class store2_manager;
 class region_model2;
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 059905e227d..be3c5149586 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -2931,6 +2931,22 @@ alloca_region2::dump_to_pp (pretty_printer *pp, bool simple) const
     pp_string (pp, "alloca_region2()");
 }
 
+/* class string_region2 : public region2.  */
+
+void
+string_region2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  // TODO:
+  if (simple)
+    dump_tree (pp, m_string_cst);
+  else
+    {
+      pp_string (pp, "string_region2(");
+      dump_tree (pp, m_string_cst);
+      pp_string (pp, ")");
+    }
+}
+
 /* class region_model2_manager.  */
 
 region_model2_manager::region_model2_manager ()
@@ -2972,6 +2988,9 @@ region_model2_manager::~region_model2_manager ()
   for (globals_map_t::iterator iter = m_globals_map.begin ();
        iter != m_globals_map.end (); ++iter)
     delete (*iter).second;
+  for (string_map_t::iterator iter = m_string_map.begin ();
+       iter != m_string_map.end (); ++iter)
+    delete (*iter).second;
 }
 
 /* svalue2 consolidation.  */
@@ -3092,6 +3111,8 @@ region_model2_manager::get_region_for_global (tree expr,
   return reg;
 }
 
+/* FIXME.  */
+
 region2 *
 region_model2_manager::get_field_region (region2 *parent, tree field,
 					 region_model2_context */*ctxt*/)
@@ -3101,6 +3122,8 @@ region_model2_manager::get_field_region (region2 *parent, tree field,
   return const_cast <region2 *> (m_fields.consolidate (field_reg));
 }
 
+/* FIXME.  */
+
 region2 *
 region_model2_manager::get_element_region (region2 *parent,
 					   tree element_type,
@@ -3113,6 +3136,8 @@ region_model2_manager::get_element_region (region2 *parent,
   return const_cast <region2 *> (m_elements.consolidate (element_reg));
 }
 
+/* FIXME.  */
+
 frame_region2 *
 region_model2_manager::get_frame_region (frame_region2 *calling_frame,
 					 function *fun)
@@ -3125,6 +3150,8 @@ region_model2_manager::get_frame_region (frame_region2 *calling_frame,
   return const_cast <frame_region2 *> (m_frames.consolidate (frame_reg));
 }
 
+/* FIXME.  */
+
 region2 *
 region_model2_manager::get_symbolic_region (svalue2 *sval)
 {
@@ -3136,6 +3163,23 @@ region_model2_manager::get_symbolic_region (svalue2 *sval)
 
 /* FIXME.  */
 
+string_region2 *
+region_model2_manager::get_region_for_string (tree string_cst)
+{
+  gcc_assert (TREE_CODE (string_cst) == STRING_CST);
+
+  string_region2 **slot = m_string_map.get (string_cst);
+  if (slot)
+    return *slot;
+  string_region2 *reg
+    = new string_region2 (alloc_region_id (), &m_root_region, string_cst);
+  // FIXME: is there a better choice of parent region?
+  m_string_map.put (string_cst, reg);
+  return reg;
+}
+
+/* FIXME.  */
+
 region2 *
 region_model2_manager::create_region_for_heap_alloc ()
 {
@@ -3957,7 +4001,7 @@ region_model2::on_gcall (const supernode *snode,
       if (is_named_call_p (callee_fndecl, "malloc", call, 1))
 	{
 	  tree size_arg = gimple_call_arg (call, 0);
-	  svalue2 *size_sval = get_rvalue (size_arg, NULL);
+	  svalue2 *size_sval = get_rvalue (size_arg, ctxt);
 	  region2 *new_reg = create_region_for_heap_alloc (size_sval);
 	  if (lhs_reg)
 	    {
@@ -3973,7 +4017,7 @@ region_model2::on_gcall (const supernode *snode,
       else if (is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
 	{
 	  tree size_arg = gimple_call_arg (call, 0);
-	  svalue2 *size_sval = get_rvalue (size_arg, NULL);
+	  svalue2 *size_sval = get_rvalue (size_arg, ctxt);
 	  region2 *new_reg = create_region_for_alloca (size_sval);
 	  if (lhs_reg)
 	    {
@@ -3982,6 +4026,25 @@ region_model2::on_gcall (const supernode *snode,
 	    }
 	  return true;
 	}
+      else if (is_named_call_p (callee_fndecl, "strlen", call, 1))
+	{
+	  tree arg = gimple_call_arg (call, 0);
+	  svalue2 *arg_sval = get_rvalue (arg, ctxt);
+	  region2 *buf_reg = deref_rvalue (arg_sval, ctxt);
+	  if (string_region2 *str_reg = buf_reg->dyn_cast_string_region2 ())
+	    {
+	      tree str_cst = str_reg->get_string_cst ();
+	      /* TREE_STRING_LENGTH is sizeof, not strlen.  */
+	      int sizeof_cst = TREE_STRING_LENGTH (str_cst);
+	      int strlen_cst = sizeof_cst - 1;
+	      tree t_cst = build_int_cst (lhs_type, strlen_cst);
+	      svalue2 *result_sval
+		= m_mgr->get_or_create_constant_svalue2 (t_cst);
+	      set_value (lhs_reg, result_sval, ctxt);
+	      return true;
+	    }
+	  /* Otherwise an unknown value.  */
+	}
     }
 
   return true;
@@ -4638,18 +4701,12 @@ region_model2::get_lvalue_1 (path_var pv,
 	return cst_reg;
       }
       break;
+#endif
 
     case STRING_CST:
-      {
-	tree cst_type = TREE_TYPE (expr);
-	array_region2 *cst_region2 = new array_region2 (m_root_reg, cst_type);
-	region2 *cst_reg = add_region2 (cst_region2);
-	svalue2 *cst_sval = get_or_create_constant_svalue2 (expr);
-	cst_region2->set_value (*this, cst_reg, cst_sval, ctxt);
-	return cst_reg;
-      }
-      break;
+      return m_mgr->get_region_for_string (expr);
 
+#if 0
     case NOP_EXPR:
     case VIEW_CONVERT_EXPR:
       {
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index f01541de334..18c47397821 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -755,7 +755,8 @@ namespace ana {
      field_region2 (RK_FIELD)
      element_region2 (RK_ELEMENT)
      heap_allocated_region2 (RK_HEAP_ALLOCATED)
-     alloca_region2 (RK_ALLOCA).  */
+     alloca_region2 (RK_ALLOCA)
+     string_region2 (RK_STRING).  */
 
 /* Abstract base class representing a chunk of memory.
 
@@ -789,7 +790,8 @@ public:
    RK_FIELD,
    RK_ELEMENT,
    RK_HEAP_ALLOCATED,
-   RK_ALLOCA
+   RK_ALLOCA,
+   RK_STRING
   };
   static const char *kind_to_str (enum kind);
 
@@ -810,6 +812,7 @@ public:
   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; }
+  virtual string_region2 *dyn_cast_string_region2 () { return NULL; }
 
   region2 *get_parent_region () const { return m_parent; }
   const region2 *get_base_region () const;
@@ -1509,6 +1512,34 @@ protected:
 #endif
 };
 
+/* A region for a STRING_CST.  */
+
+class string_region2 : public region2
+{
+public:
+  string_region2 (unsigned id, region2 *parent, tree string_cst)
+  : region2 (id, parent, TREE_TYPE (string_cst)), m_string_cst (string_cst)
+  {}
+
+  string_region2 *dyn_cast_string_region2 () FINAL OVERRIDE { return this; }
+
+#if 0
+  bool compare_fields (const element_region2 &other) const;
+#endif
+  enum region2::kind get_kind () const FINAL OVERRIDE { return RK_STRING; }
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+
+  tree get_string_cst () const { return m_string_cst; }
+
+protected:
+#if 0
+  void add_to_hash (inchash::hash &hstate) const OVERRIDE;
+#endif
+private:
+  tree m_string_cst;
+};
+
 /* A class responsible for owning and consolidating region2 and svalue2
    instances.    */
 
@@ -1543,6 +1574,7 @@ public:
   frame_region2 *get_frame_region (frame_region2 *calling_frame,
 				   function *fun);
   region2 *get_symbolic_region (svalue2 *sval);
+  string_region2 *get_region_for_string (tree string_cst);
 
   unsigned alloc_region_id () { return m_next_region_id++; }
 
@@ -1599,6 +1631,9 @@ private:
   uniq_manager<frame_region2> m_frames;
   uniq_manager<region2> m_symbolic_regions;
 
+  typedef hash_map<tree, string_region2 *> string_map_t;
+  string_map_t m_string_map;
+
   store2_manager m_store2_mgr;
 
   /* "Dynamically-allocated" region2 instances.
-- 
2.26.2

