From cc476eeb792426665ed55eaaea13da4905ab3650 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 28 Mar 2019 15:27:58 -0400
Subject: [PATCH 163/217] FIXME: engine::prune_path: update var for phi nodes

---
 gcc/analyzer/engine.cc                         | 70 +++++++++++++++++---------
 gcc/analyzer/supergraph.cc                     | 20 ++++++++
 gcc/analyzer/supergraph.h                      |  2 +
 gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c | 12 ++---
 4 files changed, 73 insertions(+), 31 deletions(-)

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 2bd6c02..c3df201 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -809,6 +809,12 @@ public:
       }
   }
 
+  const cfg_superedge& get_cfg_superedge () const
+  {
+    gcc_assert (m_edge->m_kind == SUPEREDGE_CFG_EDGE);
+    return *m_edge->dyn_cast_cfg_superedge ();
+  }
+
   const call_superedge& get_call_superedge () const
   {
     gcc_assert (m_edge->m_kind != SUPEREDGE_CFG_EDGE);
@@ -1789,25 +1795,13 @@ engine::on_phi (const supernode *node, const gphi *phi,
       log ("phi: %s", pp_formatted_text (&pp));
       log ("sm_inst: %s", sm_inst->to_str (m_sm).c_str ());
     }
-  
+
   gcc_assert (last_edge);
   const cfg_superedge *last_cfg_superedge = last_edge->dyn_cast_cfg_superedge ();
   gcc_assert (last_cfg_superedge);
   // FIXME: this ought to be an as_a<>
 
-  /* How to get from edge to phi arg?
-     PP shows: gimple_phi_arg_edge (phi, i)->src;
-     which is EDGE_PRED (gimple_bb (phi), i);
-     i.e. a lookup by index within bb->preds based on index within 
-     Aha:
-       gimple_phi_arg_location_from_edge (gphi *phi, edge e)
-       {
-         return gimple_phi_arg (phi, e->dest_idx)->locus;
-       }
-       which implies we can use the e->dest_idx to get at the phi arg.  */
-
-  size_t index = last_cfg_superedge->m_cfg_edge->dest_idx;
-  tree src = gimple_phi_arg_def (const_cast <gphi *> (phi), index); // FIXME const_cast
+  tree src = last_cfg_superedge->get_phi_arg (phi);
   tree lhs = gimple_phi_result (phi);
   on_assignment (node, phi, sm_inst, old_sm_inst, ps->make_path_var (lhs),
 		 ps->make_path_var (src), b, ps);
@@ -3163,16 +3157,44 @@ engine::prune_path (checker_path *path,
 	    switch (event->m_edge->m_kind)
 	      {
 	      case SUPEREDGE_CFG_EDGE:
-		/* TODO: is this edge significant to var?
-		   See if var can be in other states in the dest, but not
-		   in other states in the src?
-		   Must have multiple sibling edges.  */
-		// TODO: for now, filter all intraprocedural edges:
-		if (m_verbosity < 2)
-		  {
-		    log ("filtering event %i: CFG edge", idx);
-		    path->delete_event (idx);
-		  }
+		{
+		  const cfg_superedge& cfg_superedge
+		    = event->get_cfg_superedge ();
+		  const supernode *dest = event->m_edge->m_dest;
+		  /* Do we have an SSA_NAME defined via a phi node in
+		     the dest CFG node?  */
+		  if (TREE_CODE (var) == SSA_NAME)
+		    if (SSA_NAME_DEF_STMT (var)->bb == dest->m_bb)
+		      {
+			if (const gphi *phi
+			    = dyn_cast <gphi *> (SSA_NAME_DEF_STMT (var)))
+			  {
+			    /* Update var based on its phi node.  */
+			    tree old_var = var;
+			    var = cfg_superedge.get_phi_arg (phi);
+			    log ("updating from %qE to %qE based on phi node",
+				 old_var, var);
+			    if (get_logger ())
+			      {
+				pretty_printer pp;
+				pp_gimple_stmt_1 (&pp, (gimple *)phi, 0, (dump_flags_t)0);
+				// FIXME: const_cast!
+				log ("  phi: %s", pp_formatted_text (&pp));
+			      }
+			  }
+		      }
+
+		  /* TODO: is this edge significant to var?
+		     See if var can be in other states in the dest, but not
+		     in other states in the src?
+		     Must have multiple sibling edges.  */
+		  // TODO: for now, filter all intraprocedural edges:
+		  if (m_verbosity < 2)
+		    {
+		      log ("filtering event %i: CFG edge", idx);
+		      path->delete_event (idx);
+		    }
+		}
 		break;
 
 	      case SUPEREDGE_CALL:
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index 1596c7c..860d704 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -694,6 +694,26 @@ cfg_superedge::dump_label_to_pp (pretty_printer *pp) const
 
 /* FIXME.  */
 
+tree
+cfg_superedge::get_phi_arg (const gphi *phi) const
+{
+  /* How to get from edge to phi arg?
+     PP shows: gimple_phi_arg_edge (phi, i)->src;
+     which is EDGE_PRED (gimple_bb (phi), i);
+     i.e. a lookup by index within bb->preds based on index within
+     Aha:
+       gimple_phi_arg_location_from_edge (gphi *phi, edge e)
+       {
+         return gimple_phi_arg (phi, e->dest_idx)->locus;
+       }
+       which implies we can use the e->dest_idx to get at the phi arg.  */
+
+  size_t index = m_cfg_edge->dest_idx;
+  return gimple_phi_arg_def (const_cast <gphi *> (phi), index); // FIXME const_cast
+}
+
+/* FIXME.  */
+
 void
 switch_cfg_superedge::dump_label_to_pp (pretty_printer *pp) const
 {
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index 782543a..c68411f 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -300,6 +300,8 @@ class cfg_superedge : public superedge
   int true_value_p () const { return get_flags () & EDGE_TRUE_VALUE; }
   int false_value_p () const { return get_flags () & EDGE_FALSE_VALUE; }
 
+  tree get_phi_arg (const gphi *phi) const;
+
   ::edge m_cfg_edge;
 };
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c
index 7de067d..14a0aad 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c
@@ -33,15 +33,11 @@ void test_2 (size_t sz)
     free (ptr);
 }
 
-/* TODO: why isn't it showing the alloca event?  */
-/* TODO: it's showing a false leak report, due to constraints not
-   ruling out an infeasible path.  */
-#if 0
 void test_3 (size_t sz)
 {
   void *ptr;
   if (sz <= LIMIT)
-    ptr = alloca (sz);
+    ptr = alloca (sz); /* { dg-message "pointer is from here" } */
   else
     ptr = malloc (sz);
 
@@ -50,6 +46,8 @@ void test_3 (size_t sz)
   /* Bug: the "sz <= LIMIT" above should have been "sz < LIMIT",
      so there's a free-of-alloca when sz == LIMIT.  */
   if (sz >= LIMIT)
-    free (ptr);
+    free (ptr); /* { dg-warning "free of 'ptr' which points to memory not on the heap" } */
 }
-#endif
+/* { dg-bogus "leak of 'ptr'" "" { xfail *-*-* } .-1 } */
+/* TODO(xfail): it's showing a false leak report, due to constraints not
+   ruling out an infeasible path ("sz > 1024" and "sz <= 1023").  */
-- 
1.8.5.3

