From 00bc0ef20633bffc066f850d1a553108cebcda4a Mon Sep 17 00:00:00 2001
From: Ubuntu <ubuntu@ip-172-31-46-230.ec2.internal>
Date: Thu, 4 Sep 2025 21:08:56 +0000
Subject: [PATCH v2 1/1] Prevent crash when retreiving LWLock tranches

GetNamedLWLockTranche() can crash if called outside
shmem_startup_hook(). Under EXEC_BACKEND, there is no provision to
copy the NamedLWLockTrancheRequestArray, whereas fork()
automatically copies it for a normal backend. Moreover, there is no
valid use case for calling GetNamedLWLockTranche() outside
shmem_startup_hook().

To address this, shmem startup is centralized in
process_shmem_startup(), with process_shmem_startup_in_progress
indicating whether we are inside this hook. This enforces that
GetNamedLWLockTranche() is only called during the startup
hook. Update documentation to reflect this behavior.

Discussion: https://www.postgresql.org/message-id/flat/CAA5RZ0v1_15QPg5Sqd2Qz5rh_qcsyCeHHmRDY89xVHcy2yt5BQ@mail.gmail.com
---
 doc/src/sgml/xfunc.sgml           |  3 ++-
 src/backend/storage/ipc/ipci.c    | 16 ++++++++++++----
 src/backend/storage/lmgr/lwlock.c |  9 +++++++++
 src/include/storage/ipc.h         |  2 ++
 4 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index da21ef56891..774d21c8734 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3743,7 +3743,8 @@ void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
 </programlisting>
       This ensures that an array of <literal>num_lwlocks</literal> LWLocks is
       available under the name <literal>tranche_name</literal>.  A pointer to
-      this array can be obtained by calling:
+      this array can be obtained in the <literal>shmem_startup_hook</literal>
+      by calling:
 <programlisting>
 LWLockPadded *GetNamedLWLockTranche(const char *tranche_name)
 </programlisting>
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 2fa045e6b0f..786c5f258c6 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -56,6 +56,7 @@
 int			shared_memory_type = DEFAULT_SHARED_MEMORY_TYPE;
 
 shmem_startup_hook_type shmem_startup_hook = NULL;
+bool		process_shmem_startup_in_progress = false;
 
 static Size total_addin_request = 0;
 
@@ -187,8 +188,7 @@ AttachSharedMemoryStructs(void)
 	/*
 	 * Now give loadable modules a chance to set up their shmem allocations
 	 */
-	if (shmem_startup_hook)
-		shmem_startup_hook();
+	process_shmem_startup();
 }
 #endif
 
@@ -243,8 +243,7 @@ CreateSharedMemoryAndSemaphores(void)
 	/*
 	 * Now give loadable modules a chance to set up their shmem allocations
 	 */
-	if (shmem_startup_hook)
-		shmem_startup_hook();
+	process_shmem_startup();
 }
 
 /*
@@ -386,3 +385,12 @@ InitializeShmemGUCs(void)
 	sprintf(buf, "%d", num_semas);
 	SetConfigOption("num_os_semaphores", buf, PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
 }
+
+void
+process_shmem_startup(void)
+{
+	process_shmem_startup_in_progress = true;
+	if (shmem_startup_hook)
+		shmem_startup_hook();
+	process_shmem_startup_in_progress = false;
+}
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 258cdebd0f5..5249e6bc509 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -80,6 +80,7 @@
 #include "pg_trace.h"
 #include "pgstat.h"
 #include "port/pg_bitutils.h"
+#include "storage/ipc.h"
 #include "storage/proc.h"
 #include "storage/proclist.h"
 #include "storage/procnumber.h"
@@ -522,6 +523,11 @@ InitLWLockAccess(void)
  * Caller needs to retrieve the requested number of LWLocks starting from
  * the base lock address returned by this API.  This can be used for
  * tranches that are requested by using RequestNamedLWLockTranche() API.
+ *
+ * Backends may not inherit NamedLWLockTrancheRequestArray, such as
+ * EXEC_BACKEND. It's not worth the effort to guarantee this, because
+ * extensions should only need to acquire a pointer to the LWLocks in the
+ * startup hook.
  */
 LWLockPadded *
 GetNamedLWLockTranche(const char *tranche_name)
@@ -529,6 +535,9 @@ GetNamedLWLockTranche(const char *tranche_name)
 	int			lock_pos;
 	int			i;
 
+	if (!process_shmem_startup_in_progress)
+		elog(ERROR, "cannot return the address of LWLocks outside of shmem_startup_hook");
+
 	/*
 	 * Obtain the position of base address of LWLock belonging to requested
 	 * tranche_name in MainLWLockArray.  LWLocks for named tranches are placed
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index 3baf418b3d1..3a3a1d311c3 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -76,9 +76,11 @@ extern void check_on_shmem_exit_lists_are_empty(void);
 
 /* ipci.c */
 extern PGDLLIMPORT shmem_startup_hook_type shmem_startup_hook;
+extern PGDLLIMPORT bool process_shmem_startup_in_progress;
 
 extern Size CalculateShmemSize(int *num_semaphores);
 extern void CreateSharedMemoryAndSemaphores(void);
+extern void process_shmem_startup(void);
 #ifdef EXEC_BACKEND
 extern void AttachSharedMemoryStructs(void);
 #endif
-- 
2.43.0

