From d34c03b034a8ac6d806468dde16810fadaa5cbcc Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Tue, 25 Aug 2026 19:00:58 +0300
Subject: [PATCH v2 1/3] Fix backend state after a failed after-startup shmem
 request

RegisterShmemCallbacks() left the backend in a bad state, if an error
occurred in the callbacks or if an allocation failed.  Firstly,
'shmem_request_state' was left in wrong state, causing a subsequent
call to RegisterShmemCallbacks() to wrongly take the postmaster
startup codepath or assertion failures in some other functions.
Secondly, the 'pending_shmem_requests' list was not properly cleaned
up, causing a subsequent RegisterShmemCallbacks() to try to process
the stale, already-freed requests.

To fix, add a PG_TRY() block to clean those things up on error.

Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAJTYsWVRRWH48=PcuAo_2Y4Ap6M0QRmzxgUfFkNRtdWK74LjBQ@mail.gmail.com
Backpatch-through: 19
---
 src/backend/storage/ipc/shmem.c | 58 +++++++++++++++++++++------------
 1 file changed, 38 insertions(+), 20 deletions(-)

diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 228871d2525..0fadbf85a02 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -274,6 +274,7 @@ typedef struct
 static bool firstNumaTouch = true;
 
 static void CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks);
+static void ProcessShmemRequestsAfterStartup(const ShmemCallbacks *callbacks);
 static void InitShmemIndexEntry(ShmemRequest *request);
 static bool AttachShmemIndexEntry(ShmemRequest *request, bool missing_ok);
 
@@ -897,26 +898,44 @@ RegisterShmemCallbacks(const ShmemCallbacks *callbacks)
 static void
 CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks)
 {
-	bool		found_any;
-	bool		notfound_any;
-
 	Assert(shmem_request_state == SRS_DONE);
-	shmem_request_state = SRS_REQUESTING;
-
-	/*
-	 * Call the request callback first.  The callback makes ShmemRequest*()
-	 * calls for each shmem area, adding them to pending_shmem_requests.
-	 */
 	Assert(pending_shmem_requests == NIL);
-	if (callbacks->request_fn)
-		callbacks->request_fn(callbacks->opaque_arg);
-	shmem_request_state = SRS_AFTER_STARTUP_ATTACH_OR_INIT;
 
-	if (pending_shmem_requests == NIL)
+	PG_TRY();
+	{
+		/*
+		 * Call the request callback first.  The callback makes
+		 * ShmemRequest*() calls for each shmem area, adding them to
+		 * pending_shmem_requests.
+		 */
+		shmem_request_state = SRS_REQUESTING;
+		if (callbacks->request_fn)
+			callbacks->request_fn(callbacks->opaque_arg);
+
+		/* Process all the requests */
+		shmem_request_state = SRS_AFTER_STARTUP_ATTACH_OR_INIT;
+		if (pending_shmem_requests != NIL)
+			ProcessShmemRequestsAfterStartup(callbacks);
+	}
+	PG_FINALLY();
 	{
 		shmem_request_state = SRS_DONE;
-		return;
+		pending_shmem_requests = NIL;
 	}
+	PG_END_TRY();
+}
+
+static void
+ProcessShmemRequestsAfterStartup(const ShmemCallbacks *callbacks)
+{
+	bool		found_any;
+	bool		notfound_any;
+
+	/* There should be some requests to process */
+	Assert(pending_shmem_requests != NIL);
+
+	/* Caller manages the global state variable */
+	Assert(shmem_request_state == SRS_AFTER_STARTUP_ATTACH_OR_INIT);
 
 	/*
 	 * Hold ShmemIndexLock while we allocate all the shmem entries and run all
@@ -934,7 +953,11 @@ CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks)
 	found_any = notfound_any = false;
 	foreach_ptr(ShmemRequest, request, pending_shmem_requests)
 	{
-		if (hash_search(ShmemIndex, request->options->name, HASH_FIND, NULL))
+		ShmemIndexEnt *index_entry;
+
+		index_entry = (ShmemIndexEnt *)
+			hash_search(ShmemIndex, request->options->name, HASH_FIND, NULL);
+		if (index_entry)
 			found_any = true;
 		else
 			notfound_any = true;
@@ -952,11 +975,7 @@ CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks)
 			AttachShmemIndexEntry(request, false);
 		else
 			InitShmemIndexEntry(request);
-
-		pfree(request->options);
 	}
-	list_free_deep(pending_shmem_requests);
-	pending_shmem_requests = NIL;
 
 	/* Finish by calling the appropriate subsystem-specific callback */
 	if (found_any)
@@ -971,7 +990,6 @@ CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks)
 	}
 
 	LWLockRelease(ShmemIndexLock);
-	shmem_request_state = SRS_DONE;
 }
 
 /*
-- 
2.47.3

