From 2d2a326d8f578fd3fead5bf74e48ac639220662b Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 18 Nov 2019 21:06:27 -0500
Subject: [PATCH 59/95] [analyzer] Fix issues in diagnostic_manager::prune_path

There was a bad upper limit in diagnostic_manager::prune_path's test for
pruning redundant interprocedural pass information, leading to an ICE.

Additional, the test for pruning
  [..., call, function-entry, return, ...]
triples doesn't work for -fanalyzer-verbosity=0, which doesn't generate
function-entry events, leading to cases where -fanalyzer-verbosity=0 could
be more verbose than higher limits, e.g.:

  'test_3': events 1-4
    |
    |   NN |   free (ptr);
    |      |   ^~~~~~~~~~
    |      |   |
    |      |   (1) first 'free' here
    |   NN |   called_by_test_3 ();
    |      |   ~~~~~~~~~~~~~~~~~~~
    |      |   |
    |      |   (2) calling 'called_by_test_3' from 'test_3'
    |      |   (3) returning to 'test_3' from 'called_by_test_3'
    |   NN |   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
    |      |   ~~~~~~~~~~
    |      |   |
    |      |   (4) second 'free' here; first 'free' was at (1)
    |

where the call/return would be pruned at higher verbosities.

This patch fixes the limits, and prunes the case of a [call, return] pair.

gcc/ChangeLog:
	* analyzer/diagnostic-manager.cc (diagnostic_manager::prune_path):
	When pruning [..., call, function-entry, return, ...] triples,
	fix the bounds test and move it inside the loop.  Also test for
	[..., call, return, ...] pairs.

gcc/testsuite/ChangeLog:
	* gcc.dg/analyzer/analyzer-verbosity-0.c: Add coverage for pruning
	a call/return to an empty function.
	* gcc.dg/analyzer/analyzer-verbosity-1.c: Likewise.
	* gcc.dg/analyzer/analyzer-verbosity-2.c: Likewise.
---
 gcc/analyzer/diagnostic-manager.cc                 | 32 ++++++++++++++++++++--
 .../gcc.dg/analyzer/analyzer-verbosity-0.c         | 29 ++++++++++++++++++++
 .../gcc.dg/analyzer/analyzer-verbosity-1.c         | 30 ++++++++++++++++++++
 .../gcc.dg/analyzer/analyzer-verbosity-2.c         | 30 ++++++++++++++++++++
 4 files changed, 118 insertions(+), 3 deletions(-)

diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 926900b..8cd4507 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -1076,10 +1076,12 @@ diagnostic_manager::prune_path (checker_path *path,
   do
     {
       changed = false;
-      int idx = path->m_events.length () - 3;
-      while (idx >= 0 && idx < (signed)path->m_events.length ())
+      int idx = path->m_events.length () - 1;
+      while (idx >= 0)
 	{
-	  if (path->m_events[idx]->is_call_p ()
+	  /* Prune [..., call, function-entry, return, ...] triples.  */
+	  if (idx + 2 < (signed)path->m_events.length ()
+	      && path->m_events[idx]->is_call_p ()
 	      && path->m_events[idx + 1]->is_function_entry_p ()
 	      && path->m_events[idx + 2]->is_return_p ())
 	    {
@@ -1095,7 +1097,31 @@ diagnostic_manager::prune_path (checker_path *path,
 	      path->delete_event (idx + 1);
 	      path->delete_event (idx);
 	      changed = true;
+	      idx--;
+	      continue;
 	    }
+
+	  /* Prune [..., call, return, ...] pairs
+	     (for -fanalyzer-verbosity=0).  */
+	  if (idx + 1 < (signed)path->m_events.length ()
+	      && path->m_events[idx]->is_call_p ()
+	      && path->m_events[idx + 1]->is_return_p ())
+	    {
+	      if (get_logger ())
+		{
+		  label_text desc (path->m_events[idx]->get_desc (false));
+		  log ("filtering events %i-%i:"
+		       " irrelevant call/return: %s",
+		       idx, idx + 1, desc.m_buffer);
+		  desc.maybe_free ();
+		}
+	      path->delete_event (idx + 1);
+	      path->delete_event (idx);
+	      changed = true;
+	      idx--;
+	      continue;
+	    }
+
 	  idx--;
 	}
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c
index 98200b3..1103cc6 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c
@@ -131,3 +131,32 @@ void test_2 (void *ptr, int a, int b)
 
 // TODO: range cases
 
+/* The call/return to this function shouldn't appear in the path.  */
+
+void called_by_test_3 (void)
+{
+}
+
+void test_3 (void *ptr)
+{
+  free (ptr);
+  called_by_test_3 ();
+  free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
+}
+
+/* { dg-begin-multiline-output "" }
+   NN |   free (ptr);
+      |   ^~~~~~~~~~
+  'test_3': events 1-2
+    |
+    |   NN |   free (ptr);
+    |      |   ^~~~~~~~~~
+    |      |   |
+    |      |   (1) first 'free' here
+    |   NN |   called_by_test_3 ();
+    |   NN |   free (ptr);
+    |      |   ~~~~~~~~~~
+    |      |   |
+    |      |   (2) second 'free' here; first 'free' was at (1)
+    |
+  { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c
index 7e437bb..80039d5 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c
@@ -158,3 +158,33 @@ void test_2 (void *ptr, int a, int b)
            |      |   (8) second 'free' here; first 'free' was at (4)
            |
   { dg-end-multiline-output "" } */
+
+/* The call/return to this function shouldn't appear in the path.  */
+
+void called_by_test_3 (void)
+{
+}
+
+void test_3 (void *ptr)
+{
+  free (ptr);
+  called_by_test_3 ();
+  free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
+}
+
+/* { dg-begin-multiline-output "" }
+   NN |   free (ptr);
+      |   ^~~~~~~~~~
+  'test_3': events 1-2
+    |
+    |   NN |   free (ptr);
+    |      |   ^~~~~~~~~~
+    |      |   |
+    |      |   (1) first 'free' here
+    |   NN |   called_by_test_3 ();
+    |   NN |   free (ptr);
+    |      |   ~~~~~~~~~~
+    |      |   |
+    |      |   (2) second 'free' here; first 'free' was at (1)
+    |
+  { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c
index 2c9e5da..9b87d43 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c
@@ -189,3 +189,33 @@ void test_2 (void *ptr, int a, int b)
   { dg-end-multiline-output "" } */
 
 // TODO: range cases
+
+/* The call/return to this function shouldn't appear in the path.  */
+
+void called_by_test_3 (void)
+{
+}
+
+void test_3 (void *ptr)
+{
+  free (ptr);
+  called_by_test_3 ();
+  free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
+}
+
+/* { dg-begin-multiline-output "" }
+   NN |   free (ptr);
+      |   ^~~~~~~~~~
+  'test_3': events 1-2
+    |
+    |   NN |   free (ptr);
+    |      |   ^~~~~~~~~~
+    |      |   |
+    |      |   (1) first 'free' here
+    |   NN |   called_by_test_3 ();
+    |   NN |   free (ptr);
+    |      |   ~~~~~~~~~~
+    |      |   |
+    |      |   (2) second 'free' here; first 'free' was at (1)
+    |
+  { dg-end-multiline-output "" } */
-- 
1.8.5.3

