From ebacc314fd5d565e6e691ab04f52645c2ea02aa7 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 1 Nov 2019 11:59:27 -0400
Subject: [PATCH 098/119] FIXME: implement region::non_null_p; various cleanups

---
 gcc/analyzer/analyzer.h      |   1 +
 gcc/analyzer/region-model.cc | 101 +++++++++++++++++++++++++------------------
 gcc/analyzer/region-model.h  |  19 +++++---
 3 files changed, 73 insertions(+), 48 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 532adcc..900dc10 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -40,6 +40,7 @@ class svalue;
   class setjmp_svalue;
 class region;
   class map_region;
+  class symbolic_region;
 class region_model;
 class region_model_context;
   class impl_region_model_context;
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 0663e23..c3c1e90 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1537,6 +1537,7 @@ region::add_view (region_id view_rid, region_model *model)
   gcc_assert (!view_rid.null_p ());
   region *new_view = model->get_region (view_rid);
   new_view->m_is_view = true;
+  gcc_assert (!new_view->m_parent_rid.null_p ());
   gcc_assert (new_view->m_sval_id.null_p ());
 
   //gcc_assert (new_view->get_type () != NULL_TREE);
@@ -1622,6 +1623,35 @@ POP_IGNORE_WFORMAT
 
 // FIXME: what about canonicalization of m_view_rids of a region?
 
+/* Determine if a pointer to this region must be non-NULL.
+
+   Generally, pointers to regions must be non-NULL, but pointers
+   to symbolic_regions might, in fact, be NULL.
+
+   This allows us to simulate functions like malloc and calloc with:
+   - only one "outcome" from each statement,
+   - the idea that the pointer is on the heap if non-NULL
+   - the possibility that the pointer could be NULL
+   - the idea that successive values returned from malloc are non-equal
+   - to be able to zero-fill for calloc.  */
+
+bool
+region::non_null_p (const region_model &model) const
+{
+  /* Look through views to get at the underlying region.  */
+  if (is_view_p ())
+    return model.get_region (m_parent_rid)->non_null_p (model);
+
+  /* Are we within a symbolic_region?  If so, it could be NULL.  */
+  if (const symbolic_region *sym_reg = dyn_cast_symbolic_region ())
+    {
+      if (sym_reg->m_possibly_null)
+	return false;
+    }
+
+  return true;
+}
+
 /* class primitive_region : public region.  */
 
 /* Implementation of region::clone vfunc for primitive_region.  */
@@ -3384,7 +3414,8 @@ IMPL_POOL_ALLOCATOR (symbolic_region)
 /* symbolic_region's copy ctor.  */
 
 symbolic_region::symbolic_region (const symbolic_region &other)
-: region (other)
+: region (other),
+  m_possibly_null (other.m_possibly_null)
 {
 }
 
@@ -3393,10 +3424,9 @@ symbolic_region::symbolic_region (const symbolic_region &other)
    For use by region::operator==.  */
 
 bool
-symbolic_region::compare_fields (const symbolic_region &) const
+symbolic_region::compare_fields (const symbolic_region &other) const
 {
-  /* Empty.  */
-  return true;
+  return m_possibly_null == other.m_possibly_null;
 }
 
 /* Implementation of region::clone vfunc for symbolic_region.  */
@@ -4433,7 +4463,7 @@ region_model::on_call (const gcall *call, region_model_context *ctxt)
   else if (is_named_call_p (call, "__builtin_alloca", 1))
     {
       region_id frame_rid = get_current_frame_id ();
-      region_id new_rid = add_region (new symbolic_region (frame_rid));
+      region_id new_rid = add_region (new symbolic_region (frame_rid, false));
       if (!lhs_rid.null_p ())
 	{
 	  svalue_id ptr_sid
@@ -5110,7 +5140,7 @@ region_model::deref_rvalue (svalue_id ptr_sid, region_model_context *ctxt)
 	/* We need a symbolic_region to represent this unknown region.
 	   We don't know if it on the heap, stack, or a global,
 	   so use the root region as parent.  */
-	region_id new_rid = add_region (new symbolic_region (m_root_rid));
+	region_id new_rid = add_region (new symbolic_region (m_root_rid, false));
 
 	/* We need to write the region back into the pointer,
 	   or we'll get a new, different region each time.
@@ -5210,26 +5240,31 @@ region_model::eval_condition (svalue_id lhs_sid,
 	if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
 	  return constant_svalue::eval_condition (cst_lhs, op, cst_rhs);
 
-      /* If we have a region_svalue, we have a non-NULL pointer, so it does
-	 not equal zero.  */
-      if (lhs->dyn_cast_region_svalue ())
+      /* Handle comparison of a region_svalue against zero.  */
+      if (region_svalue *ptr = lhs->dyn_cast_region_svalue ())
 	if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
 	  if (zerop (cst_rhs->get_constant ()))
 	    {
-	      switch (op)
+	      /* A region_svalue is a non-NULL pointer, except in certain
+		 special cases (see the comment for region::non_null_p.  */
+	      region *pointee = get_region (ptr->get_pointee ());
+	      if (pointee->non_null_p (*this))
 		{
-		default:
-		  gcc_unreachable ();
-
-		case EQ_EXPR:
-		case GE_EXPR:
-		case LE_EXPR:
-		  return tristate::TS_FALSE;
-
-		case NE_EXPR:
-		case GT_EXPR:
-		case LT_EXPR:
-		  return tristate::TS_TRUE;
+		  switch (op)
+		    {
+		    default:
+		      gcc_unreachable ();
+
+		    case EQ_EXPR:
+		    case GE_EXPR:
+		    case LE_EXPR:
+		      return tristate::TS_FALSE;
+
+		    case NE_EXPR:
+		    case GT_EXPR:
+		    case LT_EXPR:
+		      return tristate::TS_TRUE;
+		    }
 		}
 	    }
     }
@@ -5403,7 +5438,7 @@ region_model::add_new_malloc_region ()
 {
   region_id heap_rid
     = get_root_region ()->ensure_heap_region (this);
-  return add_region (new symbolic_region (heap_rid));
+  return add_region (new symbolic_region (heap_rid, true));
 
 #if 0
 #error
@@ -5940,7 +5975,7 @@ make_region_for_type (region_id parent_rid, tree type)
 
   /* If we have a void *, make a new symbolic region.  */
   if (type == void_type_node)
-    return new symbolic_region (parent_rid);
+    return new symbolic_region (parent_rid, false);
 
   gcc_unreachable ();
 }
@@ -6497,22 +6532,6 @@ region_model::get_or_create_mem_ref (tree type,
   return get_or_create_view (element_rid, type);
 }
 
-/* FIXME.  */
-
-region_id
-region_model::get_element_FIXME (tree type,
-				 tree ptr_type,
-				 region_id raw_rid,
-				 svalue_id index_sid,
-				 region_model_context *ctxt)
-{
-  // FIXME
-  /* We now need a view as an array region of raw_rid, so we
-     can do the offset.  */
-
-}
-
-
 /* Get a region of type TYPE for PTR_SID + OFFSET_SID.
 
    If OFFSET_SID is known to be zero, then dereference PTR_SID.
@@ -6526,11 +6545,11 @@ region_model::get_or_create_pointer_plus_expr (tree type,
 					       svalue_id offset_in_bytes_sid,
 					       region_model_context *ctxt)
 {
+#if 0
   // FIXME:
   svalue *ptr_sval = get_svalue (ptr_sid);
   svalue *offset_in_bytes_sval = get_svalue (offset_in_bytes_sid);
   svalue_id offset_in_elements_sid;
-#if 0
   if (tree offset_in_bytes_cst = maybe_get_constant (offset_in_bytes_sid))
     {
       //tree offset_in_elements_cst = ;
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 6706e97..72edc3a 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -865,6 +865,8 @@ public:
 
   virtual enum region_kind get_kind () const = 0;
   virtual map_region *dyn_cast_map_region () { return NULL; }
+  virtual const symbolic_region *dyn_cast_symbolic_region () const
+  { return NULL; }
 
   region_id get_parent () const { return m_parent_rid; }
   region *get_parent_region (const region_model &model) const;
@@ -912,6 +914,8 @@ public:
 
   void validate (const region_model *model) const;
 
+  bool non_null_p (const region_model &model) const;
+
  protected:
   region (region_id parent_rid, svalue_id sval_id, tree type);
   region (const region &other);
@@ -1582,11 +1586,15 @@ public:
   static void *operator new (size_t sz);
   static void operator delete (void* ptr, size_t sz);
 
-  symbolic_region (region_id parent_rid)
-  : region (parent_rid, svalue_id::null (), NULL_TREE)
+  symbolic_region (region_id parent_rid, bool possibly_null)
+  : region (parent_rid, svalue_id::null (), NULL_TREE),
+    m_possibly_null (possibly_null)
   {}
   symbolic_region (const symbolic_region &other);
 
+  const symbolic_region *dyn_cast_symbolic_region () const FINAL OVERRIDE
+  { return this; }
+
   bool compare_fields (const symbolic_region &other) const;
 
   region *clone () const FINAL OVERRIDE;
@@ -1594,6 +1602,8 @@ public:
   enum region_kind get_kind () const FINAL OVERRIDE { return RK_SYMBOLIC; }
 
   void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
+
+  bool m_possibly_null;
 };
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1783,11 +1793,6 @@ class region_model
 				   svalue_id ptr_sid,
 				   svalue_id offset_sid,
 				   region_model_context *ctxt);
-  region_id get_element_FIXME (tree type,
-			       tree ptr_type,
-			       region_id raw_rid,
-			       svalue_id index_sid,
-			       region_model_context *ctxt);
   region_id get_or_create_pointer_plus_expr (tree type,
 					     svalue_id ptr_sid,
 					     svalue_id offset_sid,
-- 
1.8.5.3

