(new thread)

On Tue, Feb 17, 2026 at 03:30:57PM -0600, Nathan Bossart wrote:
> On Tue, Feb 17, 2026 at 11:18:00PM +0200, Heikki Linnakangas wrote:
>> On 14/02/2026 23:56, Andres Freund wrote:
>>> We really need some instrumentation that fails if we do allocations in 
>>> signal
>>> handlers etc.
>> 
>> Yeah, that would be nice..
> 
> In theory we could pretty easily add assertions for that, given the
> wrapper_handler business added a couple of years ago.  I'll put together a
> patch...

As promised...  Fortunately, check-world didn't uncover any existing
issues.  I was able to manually verify the assertion by switching a
background worker to use bgworker_die() and sending it SIGTERM.  Probably
could use some additional commentary, which I'll add if the idea seems
reasonable to you.

-- 
nathan
>From 139f33bcc5ac0fb0e63638fd509eda6a2ad3ddd2 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Tue, 17 Feb 2026 16:24:12 -0600
Subject: [PATCH v1 1/1] Add an assertion that you don't palloc in a signal
 handler.

---
 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)

Reply via email to