From 31e5903d91d13ecd562eee61d700ba690c4ffb38 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 30 Oct 2019 09:32:46 -0400
Subject: [PATCH 089/119] FIXME: implement unions; fixup some test cases

---
 gcc/analyzer/region-model.cc                  | 52 ++++++++++++++++-----------
 gcc/analyzer/region-model.h                   |  8 +++--
 gcc/testsuite/gcc.dg/analyzer/data-model-1.c  | 34 +++++++-----------
 gcc/testsuite/gcc.dg/analyzer/data-model-13.c | 12 +++++--
 gcc/testsuite/gcc.dg/analyzer/data-model-17.c | 20 +++++++++++
 5 files changed, 78 insertions(+), 48 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/data-model-17.c

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index d973acf..3595b1a 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1518,7 +1518,7 @@ region::remap_region_ids (const region_id_map &map)
   map.update (&m_active_view_rid);
 }
 
-/* FIXME.  */
+/* Add a new region with id VIEW_RID as a view of this region.  */
 
 void
 region::add_view (region_id view_rid, region_model *model)
@@ -1536,7 +1536,8 @@ region::add_view (region_id view_rid, region_model *model)
   m_view_rids.safe_push (view_rid);
 }
 
-/* FIXME.  */
+/* Look for a view of type TYPE of this region, returning its id if found,
+   or null otherwise.  */
 
 region_id
 region::get_view (tree type, region_model *model) const
@@ -2249,7 +2250,7 @@ array_region::get_element (region_model *model,
    }
 
   // FIXME: integrate with offset-based add_view:
-  return model->add_view (this_rid, element_type);
+  return model->get_or_create_view (this_rid, element_type);
 
 #if 0
 
@@ -4008,8 +4009,8 @@ region_model::on_assignment (const gassign *assign, region_model_context *ctxt)
 	/* FIXME: offset is in bytes; we presumably want to
 	   map back to an index.  */
 #endif
-	region_id view_rid = add_view (TREE_TYPE (lhs),
-				       ptr_sid, offset_sid, ctxt);
+	region_id view_rid = get_or_create_view (TREE_TYPE (lhs),
+						 ptr_sid, offset_sid, ctxt);
 
 	svalue_id element_ptr_sid
 	  = get_or_create_ptr_svalue (TREE_TYPE (ptr), view_rid);
@@ -4486,7 +4487,7 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
 	svalue_id offset_sid = get_rvalue (offset, ctxt);
 
 #if 1
-	return add_view (TREE_TYPE (expr), ptr_sid, offset_sid, ctxt);
+	return get_or_create_view (TREE_TYPE (expr), ptr_sid, offset_sid, ctxt);
 #else
 	return deref_rvalue (ptr, ctxt);
 #endif
@@ -4534,7 +4535,7 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
 	tree obj = TREE_OPERAND (expr, 0);
 	tree field = TREE_OPERAND (expr, 1);
 	region_id obj_rid = get_lvalue (obj, ctxt);
-	region_id struct_rid = add_view (obj_rid, TREE_TYPE (obj));
+	region_id struct_rid = get_or_create_view (obj_rid, TREE_TYPE (obj));
 	return get_field_region (obj_rid, field);
       }
       break;
@@ -4825,8 +4826,6 @@ region_model::maybe_cast (tree dst_type, svalue_id sid)
 region_id
 region_model::get_field_region (region_id struct_or_union_rid, tree field)
 {
-  // TODO: the imposition of a view should have happened already
-  //region_id view_rid = add_view (obj_rid, TREE_TYPE (field));
   struct_or_union_region *sou_reg
     = get_region<struct_or_union_region> (struct_or_union_rid);
 
@@ -4836,14 +4835,23 @@ region_model::get_field_region (region_id struct_or_union_rid, tree field)
   tree field_type = TREE_TYPE (field);
   tree field_type_with_quals = build_qualified_type (field_type, sou_quals);
 
-  region_id child_rid
-    = sou_reg->get_or_create (this, struct_or_union_rid, field,
-			      field_type_with_quals);
-#if 0
-  if (sou_reg->get_kind == RK_UNION)
-    sou_reg->add_view (child_rid);
-#endif
-  return child_rid;
+  // FIXME: maybe convert to a vfunc?
+  if (sou_reg->get_kind () == RK_UNION)
+    {
+      /* Union.
+	 Get a view of the union as a whole, with the type of the field.  */
+      region_id view_rid
+	= get_or_create_view (struct_or_union_rid, field_type_with_quals);
+      return view_rid;
+    }
+  else
+    {
+      /* Struct.  */
+      region_id child_rid
+	= sou_reg->get_or_create (this, struct_or_union_rid, field,
+				  field_type_with_quals);
+    return child_rid;
+    }
 }
 
 /* Get a region_id for referencing PTR_SID, creating a region if need be, and
@@ -6178,8 +6186,10 @@ region_model::get_value_by_name (const char *name) const
    (might be easier if we let regions know their own IDs).  */
 
 region_id
-region_model::add_view (tree type, svalue_id ptr_sid, svalue_id offset_sid,
-			region_model_context *ctxt)
+region_model::get_or_create_view (tree type,
+				  svalue_id ptr_sid,
+				  svalue_id offset_sid,
+				  region_model_context *ctxt)
 {
   svalue *ptr_sval = get_svalue (ptr_sid);
   tree ptr_type = ptr_sval->get_type ();
@@ -6188,13 +6198,13 @@ region_model::add_view (tree type, svalue_id ptr_sid, svalue_id offset_sid,
 
   // TODO: what about offset_sid
 
-  return add_view (raw_rid, type);
+  return get_or_create_view (raw_rid, type);
 }
 
 /* FIXME.  */
 
 region_id
-region_model::add_view (region_id raw_rid, tree type)
+region_model::get_or_create_view (region_id raw_rid, tree type)
 {
   region *raw_region = get_region (raw_rid);
 
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 3278563..e7b68b9 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -1704,9 +1704,11 @@ class region_model
 
   svalue_id get_value_by_name (const char *name) const;
 
-  region_id add_view (tree type, svalue_id ptr_sid, svalue_id offset_sid,
-		      region_model_context *ctxt);
-  region_id add_view (region_id raw_rid, tree type);
+  region_id get_or_create_view (tree type,
+				svalue_id ptr_sid,
+				svalue_id offset_sid,
+				region_model_context *ctxt);
+  region_id get_or_create_view (region_id raw_rid, tree type);
 
  private:
   region_id get_lvalue_1 (path_var pv, region_model_context *ctxt);
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
index 321a8c1..2618e40 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
@@ -569,21 +569,13 @@ void test_29 (struct coord *p)
   __analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
   __analyzer_eval (q->y == 107025); /* { dg-warning "TRUE" } */
 
-  __analyzer_eval (q[2].x == 109024); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "" { target *-*-* } .-1 } */
-  // TODO(xfail):
-  __analyzer_eval (q[2].y == 109025); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "" { target *-*-* } .-1 } */
-  // TODO(xfail):
+  __analyzer_eval (q[2].x == 109024); /* { dg-warning "TRUE" } */
+  __analyzer_eval (q[2].y == 109025); /* { dg-warning "TRUE" } */
 
   q += 2;
 
-  __analyzer_eval (q->x == 109024); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "" { target *-*-* } .-1 } */
-  // TODO(xfail):
-  __analyzer_eval (q->y == 109025); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "" { target *-*-* } .-1 } */
-  // TODO(xfail):  
+  __analyzer_eval (q->x == 109024); /* { dg-warning "TRUE" } */
+  __analyzer_eval (q->y == 109025); /* { dg-warning "TRUE" } */
 }
 
 void test_30 (void *ptr)
@@ -748,8 +740,6 @@ void foo (struct link *in)
   __analyzer_eval (in->next->next->next->f == 42);  /* { dg-warning "TRUE" } */
 }
 
-// TODO:
-
 union u
 {
   int i;
@@ -761,9 +751,13 @@ void test_41 (void)
   union u u;
   u.i = 42;
   __analyzer_eval (u.i == 42); /* { dg-warning "TRUE" } */
-}
+  __analyzer_eval (u.ptr == NULL); /* { dg-warning "UNKNOWN" } */
 
-// TODO: writes to a union member invalidating knowledge about other members
+  /* Writes to a union member should invalidate knowledge about other members.  */
+  u.ptr = NULL;
+  __analyzer_eval (u.ptr == NULL); /* { dg-warning "TRUE" } */
+  __analyzer_eval (u.i == 42); /* { dg-warning "UNKNOWN" } */
+}
 
 void test_42 (void)
 {
@@ -771,9 +765,7 @@ void test_42 (void)
   float f;
   i = 42;
   f = i;
-  __analyzer_eval (f == 42.0); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "" { target *-*-* } .-1 } */
-  // TODO(xfail)
+  __analyzer_eval (f == 42.0); /* { dg-warning "TRUE" } */
 }
 
 void test_43 (void)
@@ -782,9 +774,7 @@ void test_43 (void)
   float f;
   f = 42.0f;
   i = f;
-  __analyzer_eval (i == 42);  /* { dg-warning "TRUE" "" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "" { target *-*-* } .-1 } */
-  // TODO(xfail)
+  __analyzer_eval (i == 42);  /* { dg-warning "TRUE" } */
 }
 
 struct sbits
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-13.c b/gcc/testsuite/gcc.dg/analyzer/data-model-13.c
index a746a89..e7cb845 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-13.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-13.c
@@ -6,8 +6,16 @@ union
   int int_val;
 } global_union;
 
-void test (void)
+void test_1 (void)
 {
   global_union.ptr_val = malloc (1024);
-  global_union.int_val = 0; // FIXME: ought to complain about a leak here
 }
+
+void test_2 (void)
+{
+  global_union.ptr_val = malloc (1024); /* { dg-message "allocated here" } */
+  global_union.int_val = 0;
+} /* { dg-warning "leak of '<unknown>' " } */
+/* TODO: something better than "<unknown>".  */
+/* TODO: better location for the leak.  */
+
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-17.c b/gcc/testsuite/gcc.dg/analyzer/data-model-17.c
new file mode 100644
index 0000000..d50b84a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-17.c
@@ -0,0 +1,20 @@
+typedef struct foo {} foo_t;
+
+typedef void (*func_t)(foo_t *s);
+
+void cb_1 (foo_t *s);
+void cb_2 (foo_t *s);
+
+typedef struct config_s {
+  func_t func;
+} config;
+
+static const config table[2] = {
+  { cb_1 },
+  { cb_2 }
+};
+
+int deflate (foo_t *s, int which)
+{
+  (*(table[which].func))(s);
+}
-- 
1.8.5.3

