From 4424cbd218c3ff968d1273edf40ffc3689cc1f5d Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.ringer@2ndquadrant.com>
Date: Wed, 9 Sep 2020 12:55:29 +0800
Subject: [PATCH v999 3/3] Add guards to detect return from between PG_TRY()
 and PG_END_TRY()

These don't work because of the issue mentioned earlier where llvm's
scan-build loses track of a pointer escape when the containing struct
pointer is cleared from a global then restored to the global again.
---
 src/backend/utils/error/elog.c |  7 +++++++
 src/include/utils/elog.h       | 10 ++++++++++
 2 files changed, 17 insertions(+)

diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 9af7155171..c1fb3d4785 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -93,6 +93,9 @@ ErrorContextCallback *error_context_stack = NULL;
 
 PG_sigjmp_buf *PG_exception_stack = NULL;
 
+/* HACK for scan-build testing */
+const PG_try_guard_entry * pg_try_guard = NULL;
+
 extern bool redirection_done;
 
 /*
@@ -580,6 +583,10 @@ errfinish(const char *filename, int lineno, const char *funcname)
 
 	if (elevel >= PANIC)
 	{
+		/* trick clang into thinking we actually use pg_try_guard, hopefully... */
+		if (pg_try_guard)
+			abort();
+
 		/*
 		 * Serious crash time. Postmaster will observe SIGABRT process exit
 		 * status and kill the other backends too.
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index fe82225dbe..bf40ca632c 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -299,12 +299,21 @@ typedef struct PG_sigjmp_buf
 	sigjmp_buf buf;
 } PG_sigjmp_buf;
 
+/* HACK to show that scan-build does detect escapes from PG_CATCH() */
+typedef struct PG_try_guard_entry
+{
+	const struct PG_try_guard_entry * const previous;
+} PG_try_guard_entry;
+extern const PG_try_guard_entry * pg_try_guard;
+
 #define PG_TRY()  \
 	do { \
 		PG_sigjmp_buf *_save_exception_stack = PG_exception_stack; \
 		ErrorContextCallback *_save_context_stack = error_context_stack; \
 		PG_sigjmp_buf _local_sigjmp_buf; \
 		bool _do_rethrow = false; \
+		const PG_try_guard_entry _this_pg_try_guard = { pg_try_guard }; \
+		pg_try_guard = &_this_pg_try_guard; \
 		if (sigsetjmp(_local_sigjmp_buf.buf, 0) == 0) \
 		{ \
 			PG_exception_stack = &_local_sigjmp_buf
@@ -326,6 +335,7 @@ typedef struct PG_sigjmp_buf
 
 #define PG_END_TRY()  \
 		} \
+		pg_try_guard = _this_pg_try_guard.previous; \
 		if (_do_rethrow) \
 				PG_RE_THROW(); \
 		PG_exception_stack = _save_exception_stack; \
-- 
2.26.2

