From c5f5ed2ee4c2219bad6d9079ccb09cc51f2ff7d8 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 26 Aug 2026 00:39:31 +0300
Subject: [PATCH v2 1/1] Fix registering shmem callbacks in single-user mode

RegisterShmemCallbacks() should not be called from the postmaster
process after postmaster startup. Add an assertion for that, and fix
the check for whether it's being called for "after startup"
allocations to take single-user mode into account.

Reported-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAJTYsWU7epjUL1-xrpYeOrmkmq20M2Q22Y_SRb8PWQG8KNQyDw@mail.gmail.com
Backpatch-through: 19
---
 src/backend/storage/ipc/shmem.c               | 11 +++++++--
 .../test_shmem/t/001_late_shmem_alloc.pl      | 24 +++++++++++++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index c511395b1f0..0200bcda2cd 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -911,23 +911,30 @@ ShmemAddrIsValid(const void *addr)
 void
 RegisterShmemCallbacks(const ShmemCallbacks *callbacks)
 {
-	if (shmem_request_state == SRS_DONE && IsUnderPostmaster)
+	if (shmem_request_state == SRS_DONE)
 	{
 		/*
 		 * After-startup initialization or attachment.  Call the appropriate
 		 * callbacks immediately.
+		 *
+		 * This is not allowed from the postmaster, because the postmaster
+		 * cannot acquire locks.
 		 */
+		Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
+
 		if ((callbacks->flags & SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP) == 0)
 			elog(ERROR, "cannot request shared memory at this time");
 
 		CallShmemCallbacksAfterStartup(callbacks);
 	}
-	else
+	else if (shmem_request_state == SRS_INITIAL)
 	{
 		/* Remember the callbacks for later */
 		registered_shmem_callbacks = lappend(registered_shmem_callbacks,
 											 (void *) callbacks);
 	}
+	else
+		elog(ERROR, "cannot request shared memory at this time");
 }
 
 /*
diff --git a/src/test/modules/test_shmem/t/001_late_shmem_alloc.pl b/src/test/modules/test_shmem/t/001_late_shmem_alloc.pl
index b09889f4fb0..d2bf32a72fe 100644
--- a/src/test/modules/test_shmem/t/001_late_shmem_alloc.pl
+++ b/src/test/modules/test_shmem/t/001_late_shmem_alloc.pl
@@ -100,4 +100,28 @@ else
 }
 
 $node->stop;
+
+###
+# Test allocating memory after startup in single-user mode
+###
+SKIP:
+{
+	# Skip the test on Windows, as single-user mode would fail on permission
+	# failure with privileged accounts.
+	skip 'single-user mode is not supported on this platform', 1
+	  if $windows_os;
+
+	my $query = "SELECT get_test_shmem_attach_count();\n";
+	my $result = run_log(
+		[
+			'postgres', '--single', '-F',
+			'-c' => 'exit_on_error=true',
+			'-D' => $node->data_dir,
+			'postgres'
+		],
+		'<' => \$query);
+
+	ok($result, "shmem area is initialized in single-user mode");
+}
+
 done_testing();
-- 
2.47.3

