From abc26c67854fb800b933a16fe9b62eb559b5f3a9 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 20 Jun 2019 21:07:57 -0400
Subject: [PATCH 36/47] FIXME: double_free: add event cross-reference

---
 gcc/analyzer/hardcoded-state-machine-malloc.cc     |  4 +-
 gcc/analyzer/impl-4.cc                             | 66 ++++++++++++----------
 .../NOT_FOR_UPSTREAM-CVE-2005-1689-krb5-recvauth.c |  2 +-
 .../gcc.dg/analyzer/analyzer-verbosity-0.c         |  4 +-
 .../gcc.dg/analyzer/analyzer-verbosity-1.c         |  2 +-
 .../gcc.dg/analyzer/analyzer-verbosity-2.c         |  4 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-10.c      |  2 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-11.c      |  2 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c       |  2 +-
 .../gcc.dg/analyzer/malloc-ipa-8-double-free.c     |  2 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-paths-1.c     |  2 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-paths-2.c     |  2 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-paths-5.c     |  2 +-
 13 files changed, 52 insertions(+), 44 deletions(-)

diff --git a/gcc/analyzer/hardcoded-state-machine-malloc.cc b/gcc/analyzer/hardcoded-state-machine-malloc.cc
index ba987ab..e578cb8 100644
--- a/gcc/analyzer/hardcoded-state-machine-malloc.cc
+++ b/gcc/analyzer/hardcoded-state-machine-malloc.cc
@@ -111,9 +111,11 @@ public:
     return label_text ();
   }
 
-  /* FIXME.  */
   label_text describe (const evdesc::final_event &) FINAL OVERRIDE
   {
+    if (m_first_free_event.known_p ())
+      return formatted_print ("second %qs here; first %qs was at (%i)",
+			      "free", "free", m_first_free_event.one_based ());
     return formatted_print ("second %qs here", "free");
   }
 
diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index d1c50ec..6e9aecc 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -1613,24 +1613,53 @@ class warning_event : public checker4_event
 {
 public:
   warning_event (location_t loc, tree fndecl, int depth,
-		 const char *msg)
+		 const state_machine *sm,
+		 tree var, state_machine::state_t state)
   : checker4_event (EK_WARNING, loc, fndecl, depth),
-    m_msg (xstrdup (msg))
+    m_sm (sm), m_var (var), m_state (state)
   {
   }
-  ~warning_event () { free (m_msg); }
 
   label_text get_desc () const FINAL OVERRIDE
   {
-    return label_text::borrow (m_msg);
+    if (m_pending_diagnostic)
+      {
+	label_text ev_desc = m_pending_diagnostic->describe
+	  (evdesc::final_event (m_var, m_state));
+	if (ev_desc.m_buffer)
+	  {
+	    if (m_sm && flag_analyzer_verbose_state_changes)
+	      {
+		label_text result = label_text::take
+		  (print ("%s (%qE is in state %qs)",
+			  ev_desc.m_buffer,
+			  m_var, m_sm->get_state_name (m_state)));
+		ev_desc.maybe_free ();
+		return result;
+	      }
+	    else
+	      return ev_desc;
+	  }
+      }
+
+    if (m_sm)
+      return label_text::take
+	(print ("here (%qE is in state %qs)",
+		m_var,
+		m_sm->get_state_name (m_state)));
+    else
+      return label_text::borrow ("here");
   }
 
   warning_event *clone () const FINAL OVERRIDE
   {
-    return new warning_event (m_loc, m_fndecl, m_depth, m_msg);
+    return new warning_event (m_loc, m_fndecl, m_depth, m_sm, m_var, m_state);
   }
 
-  char *m_msg;
+private:
+  const state_machine *m_sm;
+  tree m_var;
+  state_machine::state_t m_state;
 };
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1709,35 +1738,12 @@ public:
 			tree var, state_machine::state_t state,
 			pending_diagnostic *pd)
   {
-    char *msg = NULL;
-    label_text ev_desc = pd->describe (evdesc::final_event (var, state));
-    if (ev_desc.m_buffer)
-      {
-	if (sm && flag_analyzer_verbose_state_changes)
-	  {
-	    msg = print ("%s (%qE is in state %qs)", ev_desc.m_buffer,
-			 var, sm->get_state_name (state));
-	    ev_desc.maybe_free ();
-	  }
-	else
-	  msg = ev_desc.take_or_copy ();
-      }
-    else
-      {
-	if (sm)
-	  msg = print ("here (%qE is in state %qs)", var,
-		       sm->get_state_name (state));
-	else
-	  msg = print ("here");
-	// FIXME: ideally would show the full message here, too?
-      }
     checker4_event *end_of_path
       = new warning_event (stmt->location,
 			   enode->get_function ()->decl,
 			   enode->get_stack_depth (),
-			   msg);
+			   sm, var, state);
     add_event (end_of_path);
-    free (msg);
   }
 
   void prepare_for_emission (pending_diagnostic *pd)
diff --git a/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-CVE-2005-1689-krb5-recvauth.c b/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-CVE-2005-1689-krb5-recvauth.c
index ae1ba3a..541c587 100644
--- a/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-CVE-2005-1689-krb5-recvauth.c
+++ b/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-CVE-2005-1689-krb5-recvauth.c
@@ -10847,6 +10847,6 @@ krb5_recvauth_version(krb5_context context,
                       |   NN |  free((char *)(inbuf.data));
                       |      |  ~~~~~~~~~~~~~~~~~~~~~~~~~~
                       |      |  |
-                      |      |  (20) second 'free' here
+                      |      |  (20) second 'free' here; first 'free' was at (9)
                       |
   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c
index d9e8d60..7238624 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c
@@ -53,7 +53,7 @@ void test_1 (void *ptr, int a, int b)
                   |   NN |   free (ptr);
                   |      |   ^~~~~~~~~~
                   |      |   |
-                  |      |   (5) second 'free' here
+                  |      |   (5) second 'free' here; first 'free' was at (2)
                   |
   { dg-end-multiline-output "" } */
 
@@ -121,7 +121,7 @@ void test_2 (void *ptr, int a, int b)
                   |   NN |   free (ptr);
                   |      |   ^~~~~~~~~~
                   |      |   |
-                  |      |   (5) second 'free' here
+                  |      |   (5) second 'free' here; first 'free' was at (2)
                   |
   { 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 3313670..389378b 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c
@@ -68,7 +68,7 @@ void test_1 (void *ptr, int a, int b)
                   |   NN |   free (ptr);
                   |      |   ~~~~~~~~~~
                   |      |   |
-                  |      |   (8) second 'free' here
+                  |      |   (8) second 'free' here; first 'free' was at (4)
                   |
   { 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 a4e9bde..8530c2b 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c
@@ -77,7 +77,7 @@ void test_1 (void *ptr, int a, int b)
                   |   NN |   free (ptr);
                   |      |   ~~~~~~~~~~
                   |      |   |
-                  |      |   (10) second 'free' here
+                  |      |   (10) second 'free' here; first 'free' was at (5)
                   |
   { dg-end-multiline-output "" } */
 
@@ -170,7 +170,7 @@ void test_2 (void *ptr, int a, int b)
                   |   NN |   free (ptr);
                   |      |   ~~~~~~~~~~
                   |      |   |
-                  |      |   (10) second 'free' here
+                  |      |   (10) second 'free' here; first 'free' was at (5)
                   |
   { dg-end-multiline-output "" } */
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-10.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-10.c
index 212097c..d235138 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-10.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-10.c
@@ -6,7 +6,7 @@ calls_free (void *victim) /* { dg-message "\\(3\\) entry to 'calls_free'" } */
 {
   free (victim); /* { dg-warning "double-free of 'victim'" } */
   /* { dg-message "\\(4\\) first 'free' here" "" { target *-*-* } .-1 } */
-  /* { dg-message "\\(8\\) second 'free' here" "" { target *-*-* } .-2 } */
+  /* { dg-message "\\(8\\) second 'free' here; first 'free' was at \\(4\\)" "" { target *-*-* } .-2 } */
 
   /* TODO: would this be better emitted at the callsite,
      for such a simple wrapper?  */
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-11.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-11.c
index 112b6d8..e114eed 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-11.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-11.c
@@ -88,6 +88,6 @@ void test (void *ptr)
                  |   NN |   free (victim);
                  |      |   ~~~~~~~~~~~~~
                  |      |   |
-                 |      |   (10) second 'free' here
+                 |      |   (10) second 'free' here; first 'free' was at (5)
                  |
   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
index 7edd0b0..9ced8c0 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
@@ -8,7 +8,7 @@ calls_free (void *victim) /* { dg-message "\\(3\\) entry to 'calls_free'" } */
 {
   free (victim); /* { dg-warning "double-free of 'victim'" } */
   /* { dg-message "\\(4\\) first 'free' here" "" { target *-*-* } .-1 } */
-  /* { dg-message "\\(8\\) second 'free' here" "" { target *-*-* } .-2 } */
+  /* { dg-message "\\(8\\) second 'free' here; first 'free' was at \\(4\\)" "" { target *-*-* } .-2 } */
 
   /* TODO: would this be better emitted at the callsite,
      for such a simple wrapper?  */
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-double-free.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-double-free.c
index a4ab163..29910f4 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-double-free.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-double-free.c
@@ -158,7 +158,7 @@ void test (int i)
                               |   NN |   free (ptr);
                               |      |   ~~~~~~~~~~
                               |      |   |
-                              |      |   (18) second 'free' here ('ptr' is in state 'free')
+                              |      |   (18) second 'free' here; first 'free' was at (11) ('ptr' is in state 'free')
                               |
    { dg-end-multiline-output "" } */
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-1.c
index 0e743b6..7d2f4cf 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-1.c
@@ -11,5 +11,5 @@ void test_1 (void)
   /* { dg-warning "double-free of 'ptr'"  "" { target *-*-* } second_free } */
   /* { dg-message "\\(1\\) state of 'ptr': 'start' -> 'unchecked'" "" { target *-*-* } malloc } */
   /* { dg-message "\\(2\\) first 'free' here" "" { target *-*-* } first_free } */
-  /* { dg-message "\\(3\\) second 'free' here" "" { target *-*-* } second_free } */
+  /* { dg-message "\\(3\\) second 'free' here; first 'free' was at \\(2\\)" "" { target *-*-* } second_free } */
 }
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-2.c b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-2.c
index eda86c2..17a22a9 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-2.c
@@ -9,5 +9,5 @@ void test_2 (void *ptr)
 
   /* { dg-warning "double-free of 'ptr'"  "" { target *-*-* } second_free } */
   /* { dg-message "\\(1\\) first 'free' here" "" { target *-*-* } first_free } */
-  /* { dg-message "\\(2\\) second 'free' here" "" { target *-*-* } second_free } */
+  /* { dg-message "\\(2\\) second 'free' here; first 'free' was at \\(1\\)" "" { target *-*-* } second_free } */
 }
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-5.c b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-5.c
index 76f7d7f..d2d4452 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-5.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-5.c
@@ -35,7 +35,7 @@ int test (const char *filename, int flag)
   /* { dg-message "\\(3\\) state of 'p': 'unchecked' -> 'nonnull'" "" { target *-*-* } test_of_p } */
   /* { dg-message "\\(4\\) following 'true' branch" "" { target *-*-* } test_of_q } */
   /* { dg-message "\\(5\\) first 'free' here" "" { target *-*-* } first_free_of_p } */
-  /* { dg-message "\\(6\\) second 'free' here" "" { target *-*-* } second_free_of_p } */
+  /* { dg-message "\\(6\\) second 'free' here; first 'free' was at \\(5\\)" "" { target *-*-* } second_free_of_p } */
 
   /* We don't care about the state changes to q.  */
 }
-- 
1.8.5.3

