Subject: [PATCH v1 1/1] Add an assertion that you don't palloc in a signal handler.

From: Nathan Bossart <[email-masked]>
Date: Tue, 17 Feb 2026 16:24:12 -0600

---
 src/backend/utils/mmgr/mcxt.c |  9 +++++++++
 src/include/miscadmin.h       |  3 +++
 src/port/pqsignal.c           | 10 ++++++++++
 3 files changed, 22 insertions(+)

diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 073bdb35d2a..4d79359b0b9 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -1235,6 +1235,7 @@ MemoryContextAlloc(MemoryContext context, Size size)
 
 	Assert(MemoryContextIsValid(context));
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	context->isReset = false;
 
@@ -1269,6 +1270,7 @@ MemoryContextAllocZero(MemoryContext context, Size size)
 
 	Assert(MemoryContextIsValid(context));
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	context->isReset = false;
 
@@ -1292,6 +1294,7 @@ MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
 
 	Assert(MemoryContextIsValid(context));
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) :
 		  AllocSizeIsValid(size)))
@@ -1392,6 +1395,7 @@ palloc(Size size)
 
 	Assert(MemoryContextIsValid(context));
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	context->isReset = false;
 
@@ -1422,6 +1426,7 @@ palloc0(Size size)
 
 	Assert(MemoryContextIsValid(context));
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	context->isReset = false;
 
@@ -1444,6 +1449,7 @@ palloc_extended(Size size, int flags)
 
 	Assert(MemoryContextIsValid(context));
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	context->isReset = false;
 
@@ -1637,6 +1643,7 @@ repalloc(void *pointer, Size size)
 	void	   *ret;
 
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	/* isReset must be false already */
 	Assert(!context->isReset);
@@ -1672,6 +1679,7 @@ repalloc_extended(void *pointer, Size size, int flags)
 	void	   *ret;
 
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	/* isReset must be false already */
 	Assert(!context->isReset);
@@ -1728,6 +1736,7 @@ MemoryContextAllocHuge(MemoryContext context, Size size)
 
 	Assert(MemoryContextIsValid(context));
 	AssertNotInCriticalSection(context);
+	Assert(!InSignalHandler);
 
 	context->isReset = false;
 
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index f16f35659b9..a1c89147586 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -155,6 +155,9 @@ do { \
 	CritSectionCount--; \
 } while(0)
 
+/* in port/pqsignal.c */
+extern PGDLLIMPORT volatile sig_atomic_t InSignalHandler;
+
 
 /*****************************************************************************
  *	  globals.h --															 *
diff --git a/src/port/pqsignal.c b/src/port/pqsignal.c
index fbdf9341c2f..6e036975b3c 100644
--- a/src/port/pqsignal.c
+++ b/src/port/pqsignal.c
@@ -71,6 +71,10 @@ StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG");
 
 static volatile pqsigfunc pqsignal_handlers[PG_NSIG];
 
+#ifndef FRONTEND
+volatile sig_atomic_t InSignalHandler = false;
+#endif
+
 /*
  * Except when called with SIG_IGN or SIG_DFL, pqsignal() sets up this function
  * as the handler for all signals.  This wrapper handler function checks that
@@ -99,6 +103,8 @@ wrapper_handler(SIGNAL_ARGS)
 	Assert(MyProcPid);
 	Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
 
+	InSignalHandler = true;
+
 	if (unlikely(MyProcPid != (int) getpid()))
 	{
 		pqsignal(postgres_signal_arg, SIG_DFL);
@@ -109,6 +115,10 @@ wrapper_handler(SIGNAL_ARGS)
 
 	(*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg);
 
+#ifndef FRONTEND
+	InSignalHandler = false;
+#endif
+
 	errno = save_errno;
 }
 
-- 
2.50.1 (Apple Git-155)

--pa4wzpETADBTomYH--