From 8478624e0fe294c8045f74b1d2ae6edd0d8a035a Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 21 Mar 2019 11:34:24 -0400
Subject: [PATCH 132/138] FIXME: add interprocedural test to plugin.exp

---
 .../gcc.dg/plugin/diagnostic-test-paths-4.c        |  74 ++++++++
 .../gcc.dg/plugin/diagnostic_plugin_test_paths.c   | 191 ++++++++++++++++++++-
 gcc/testsuite/gcc.dg/plugin/plugin.exp             |   3 +-
 3 files changed, 262 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c

diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c
new file mode 100644
index 0000000..edd73e5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c
@@ -0,0 +1,74 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <stdlib.h>
+
+void *wrapped_malloc (size_t size)
+{
+  return malloc (size);
+}
+
+void wrapped_free (void *ptr)
+{
+  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
+  /* { dg-begin-multiline-output "" }
+  'test': events 1-2 (depth 0)
+     | (1): entering 'test'
+     | (2): calling 'make_boxed_int'
+     +--> 'make_boxed_int': events 3-4 (depth 1)
+                  | (3): entering 'make_boxed_int'
+                  | (4): calling 'wrapped_malloc'
+                  +--> 'wrapped_malloc': events 5-6 (depth 2)
+                               | (5): entering 'wrapped_malloc'
+                               | (6): calling 'malloc'
+     <-------------------------+
+     |
+  'test': event 7 (depth 0)
+     | (7): calling 'free_boxed_int'
+     +--> 'free_boxed_int': events 8-9 (depth 1)
+                  | (8): entering 'free_boxed_int'
+                  | (9): calling 'wrapped_free'
+                  +--> 'wrapped_free': events 10-11 (depth 2)
+                              | (10): entering 'wrapped_free'
+                              | (11): calling 'free'
+     <------------------------+
+     |
+  'test': event 12 (depth 0)
+     | (12): calling 'free_boxed_int'
+     +--> 'free_boxed_int': events 13-14 (depth 1)
+                  | (13): entering 'free_boxed_int'
+                  | (14): calling 'wrapped_free'
+                  +--> 'wrapped_free': events 15-16 (depth 2)
+                              | (15): entering 'wrapped_free'
+                              | (16): calling 'free'
+     { dg-end-multiline-output "" } */
+}
+
+typedef struct boxed_int
+{
+  int i;
+} boxed_int;
+
+boxed_int *
+make_boxed_int (int i)
+{
+  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+  result->i = i;
+  return result;
+}
+
+void
+free_boxed_int (boxed_int *bi)
+{
+  wrapped_free (bi);
+}
+
+void test (int i)
+{
+  boxed_int *obj = make_boxed_int (i);
+
+  free_boxed_int (obj);
+
+  free_boxed_int (obj);
+}
+
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c
index eba4441..82d7ee9 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c
@@ -33,6 +33,7 @@
 #include "plugin-version.h"
 #include "diagnostic.h"
 #include "diagnostic-path.h"
+#include "diagnostic-metadata.h"
 #include "context.h"
 #include "print-tree.h"
 #include "gcc-rich-location.h"
@@ -106,15 +107,14 @@ check_for_named_call (gimple *stmt,
   return call;
 }
 
-/* FIXME.  */
+/* Example 1: a purely intraprocedural path.  */
 
-unsigned int
-pass_test_show_path::execute (function *)
+static void
+example_1 ()
 {
   gimple_stmt_iterator gsi;
   basic_block bb;
 
-  /* Example A: a purely intraprocedural path.  */
   gcall *call_to_PyList_Append = NULL;
   gcall *call_to_PyList_New = NULL;
   gcond *for_cond = NULL;
@@ -160,11 +160,192 @@ pass_test_show_path::execute (function *)
 		      "PyList_Append", 1);
       richloc.set_path (&path);
       error_at (&richloc,
-		"passing NULL as argument %i to %qs which requires a non-NULL parameter",
+		"passing NULL as argument %i to %qs"
+		" which requires a non-NULL parameter",
 		1, "PyList_Append");
       // TODO: show param within decl
       //inform (
     }
+}
+
+/* FIXME.  */
+
+struct event_location_t
+{
+  event_location_t ()
+  : m_fun (NULL), m_loc (UNKNOWN_LOCATION)
+  {}
+
+  event_location_t (function *fun, location_t loc)
+  : m_fun (fun), m_loc (loc)
+  {}
+
+  void set (const gimple *stmt, function *fun)
+  {
+    m_fun = fun;
+    m_loc = gimple_location (stmt);
+  }
+
+  function *m_fun;
+  location_t m_loc;
+};
+
+/* FIXME.  */
+
+static void
+check_for_named_function (function *fun, const char *funcname,
+			  event_location_t *out_entry)
+{
+  gcc_assert (fun);
+  gcc_assert (funcname);
+
+  if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fun->decl)), funcname))
+    return;
+
+  *out_entry = event_location_t (fun, fun->function_start_locus);
+}
+
+
+/* Example 2: an interprocedural path.  */
+
+class test_diagnostic_path : public simple_diagnostic_path
+{
+ public:
+  test_diagnostic_path (pretty_printer *event_pp)
+  : simple_diagnostic_path (event_pp)
+  {
+  }
+  void add_entry (event_location_t evloc, int stack_depth,
+		  const char *funcname)
+  {
+    gcc_assert (evloc.m_fun);
+    add_event (evloc.m_loc, evloc.m_fun->decl, stack_depth,
+	       "entering %qs", funcname);
+  }
+
+#if 0
+  void add_return (tree fndecl, int stack_depth)
+  {
+    add_event (UNKNOWN_LOCATION, fndecl, stack_depth,
+	       "returning to %qE", fndecl);
+  }
+#endif
+  void add_call (event_location_t call_evloc, int caller_stack_depth,
+		 event_location_t callee_entry_evloc, const char *callee)
+  {
+    gcc_assert (call_evloc.m_fun);
+    add_event (call_evloc.m_loc, call_evloc.m_fun->decl, caller_stack_depth,
+	       "calling %qs", callee);
+    add_entry (callee_entry_evloc, caller_stack_depth + 1, callee);
+  }
+
+  void add_leaf_call (event_location_t call_evloc, int caller_stack_depth,
+		      const char *callee)
+  {
+    gcc_assert (call_evloc.m_fun);
+    add_event (call_evloc.m_loc, call_evloc.m_fun->decl, caller_stack_depth,
+	       "calling %qs", callee);
+  }
+};
+
+static void
+example_2 ()
+{
+  gimple_stmt_iterator gsi;
+  basic_block bb;
+
+  event_location_t entry_to_wrapped_malloc;
+  event_location_t call_to_malloc;
+
+  event_location_t entry_to_wrapped_free;
+  event_location_t call_to_free;
+
+  event_location_t entry_to_make_boxed_int;
+  event_location_t call_to_wrapped_malloc;
+
+  event_location_t entry_to_free_boxed_int;
+  event_location_t call_to_wrapped_free;
+
+  event_location_t entry_to_test;
+  event_location_t call_to_make_boxed_int;
+  event_location_t call_to_free_boxed_int;
+
+  cgraph_node *node;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+    {
+      function *fun = node->get_fun ();
+      FOR_EACH_BB_FN (bb, fun)
+	{
+	  check_for_named_function (fun, "wrapped_malloc",
+				    &entry_to_wrapped_malloc);
+	  check_for_named_function (fun, "wrapped_free",
+				    &entry_to_wrapped_free);
+	  check_for_named_function (fun, "make_boxed_int",
+				    &entry_to_make_boxed_int);
+	  check_for_named_function (fun, "free_boxed_int",
+				    &entry_to_free_boxed_int);
+	  check_for_named_function (fun, "test",
+				    &entry_to_test);
+
+	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	    {
+	      gimple *stmt = gsi_stmt (gsi);
+	      if (gcall *call = check_for_named_call (stmt, "malloc", 1))
+		call_to_malloc.set (call, fun);
+	      if (gcall *call = check_for_named_call (stmt, "free", 1))
+		call_to_free.set (call, fun);
+	      if (gcall *call = check_for_named_call (stmt, "wrapped_malloc", 1))
+		call_to_wrapped_malloc.set (call, fun);
+	      if (gcall *call = check_for_named_call (stmt, "wrapped_free", 1))
+		call_to_wrapped_free.set (call, fun);
+	      if (gcall *call = check_for_named_call (stmt, "make_boxed_int", 1))
+		call_to_make_boxed_int.set (call, fun);
+	      if (gcall *call = check_for_named_call (stmt, "free_boxed_int", 1))
+		call_to_free_boxed_int.set (call, fun);
+	    }
+	}
+    }
+
+  if (call_to_malloc.m_fun)
+    {
+      auto_diagnostic_group d;
+
+      gcc_rich_location richloc (call_to_free.m_loc);
+      test_diagnostic_path path (global_dc->printer);
+      path.add_entry (entry_to_test, 0, "test");
+      path.add_call (call_to_make_boxed_int, 0,
+		     entry_to_make_boxed_int, "make_boxed_int");
+      path.add_call (call_to_wrapped_malloc, 1,
+		     entry_to_wrapped_malloc, "wrapped_malloc");
+      path.add_leaf_call (call_to_malloc, 2, "malloc");
+
+      for (int i = 0; i < 2; i++)
+	{
+	  path.add_call (call_to_free_boxed_int, 0,
+			 entry_to_free_boxed_int, "free_boxed_int");
+	  path.add_call (call_to_wrapped_free, 1,
+			 entry_to_wrapped_free, "wrapped_free");
+	  path.add_leaf_call (call_to_free, 2, "free");
+	}
+
+      richloc.set_path (&path);
+
+      diagnostic_metadata m;
+      m.add_cwe (415); /* CWE-415: Double Free.  */
+
+      warning_at (&richloc, m,
+		  "double-free of %qs", "ptr");
+    }
+}
+
+
+/* FIXME.  */
+
+unsigned int
+pass_test_show_path::execute (function *)
+{
+  example_1 ();
+  example_2 ();
 
   return 0;
 }
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 635a387..df7f48d 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -59,7 +59,8 @@ set plugin_test_list [list \
     { diagnostic_plugin_test_paths.c \
 	  diagnostic-test-paths-1.c \
 	  diagnostic-test-paths-2.c \
-	  diagnostic-test-paths-3.c } \
+	  diagnostic-test-paths-3.c \
+	  diagnostic-test-paths-4.c } \
 ]
 
 foreach plugin_test $plugin_test_list {
-- 
1.8.5.3

