From 1d1aafdbe6b640ab66ec2fcf77852ba1bd7df084 Mon Sep 17 00:00:00 2001
From: Onur Tirtir <onurcantirtir@gmail.com>
Date: Thu, 23 Mar 2023 20:04:59 +0300
Subject: [PATCH v2] Report the query string that caused a memory error

If we run multiple queries under Valgrind, it becomes quite hard to
understand which query caused a memory error by looking into the stack
traces that Valgrind reported.

For this reason, this patch introduces some changes to
PostgresMain() to report the messages that cause memory errors. At
the high-level:
* We compare number of memory errors reported by Valgrind before and
  after this message-run by using VALGRIND_COUNT_ERRORS macro provided
  in valgrind.h.
* If the message caused a memory error, then we report this query to
  Valgrind log file (right after the relevant stack trace) by
  using VALGRIND_PRINTF macro provided in valgrind.h.
---
 src/backend/tcop/postgres.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index cab709b07b..aeb8ad34d7 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -73,6 +73,9 @@
 #include "utils/snapmgr.h"
 #include "utils/timeout.h"
 #include "utils/timestamp.h"
+#ifdef USE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif
 
 /* ----------------
  *		global variables
@@ -4070,6 +4073,9 @@ PostgresMain(const char *dbname, const char *username)
 	volatile bool send_ready_for_query = true;
 	bool		idle_in_transaction_timeout_enabled = false;
 	bool		idle_session_timeout_enabled = false;
+#ifdef USE_VALGRIND
+	unsigned	valgrind_errors_before_message = 0;
+#endif
 
 	Assert(dbname != NULL);
 	Assert(username != NULL);
@@ -4365,6 +4371,10 @@ PostgresMain(const char *dbname, const char *username)
 
 	for (;;)
 	{
+#ifdef USE_VALGRIND
+		valgrind_errors_before_message = VALGRIND_COUNT_ERRORS;
+#endif
+
 		/*
 		 * At top of loop, reset extended-query-message flag, so that any
 		 * errors encountered in "idle" state don't provoke skip.
@@ -4802,6 +4812,22 @@ PostgresMain(const char *dbname, const char *username)
 						 errmsg("invalid frontend message type %d",
 								firstchar)));
 		}
+
+#ifdef USE_VALGRIND
+
+		/*
+		 * Report the message (and its type) that caused a memory error if
+		 * it's not something that resulted in a backend exit or an ereport()
+		 * call.
+		 */
+		if (VALGRIND_COUNT_ERRORS > valgrind_errors_before_message)
+		{
+			VALGRIND_PRINTF("The message for which valgrind reported a "
+							"memory error was (of type '%c'):\n%s\n\n",
+							firstchar,
+							input_message.len ? input_message.data : "(empty)");
+		}
+#endif
 	}							/* end of input-reading loop */
 }
 
-- 
2.25.1

