From 52395326c677e09284365f831d7b4d9838c3a76a Mon Sep 17 00:00:00 2001
From: Sami Imseih <simseih@amazon.com>
Date: Fri, 29 Aug 2025 08:13:42 -0500
Subject: [PATCH v18 3/4] Fix EXEC_BACKEND segfault on
 NamedLWLockTrancheRequestArray access

Unlike fork(), EXEC_BACKEND did not pass NamedLWLockTrancheRequestArray
down to backends. This caused crashes if backends accessed the array,
such as in GetNamedLWLockTranche.

This patch fixes the issue by adding a num_lwlocks field to the shared
memory NamedLWLockTrancheArray, with the postmaster copying the value
from NamedLWLockTrancheRequestArray. GetNamedLWLockTranche now looks up
the LWLock from NamedLWLockTrancheArray instead.

NamedLWLockTrancheArray already points to shared memory and is passed
down to backends in launch_backend.c. NamedLWLockTrancheRequests still
acts as the counter for both arrays and is already handled in
EXEC_BACKEND, so no further changes are needed there.

This issue was discovered during testing of nearby code. No reports have
been seen in the field, so backpatching is not required.
---
 src/backend/postmaster/launch_backend.c |  2 +-
 src/backend/storage/lmgr/lwlock.c       | 55 ++++++++++++++-----------
 src/include/storage/lwlock.h            |  8 +++-
 3 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index cbb44344b5a..5a495217c5b 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -101,7 +101,7 @@ typedef struct
 	struct InjectionPointsCtl *ActiveInjectionPoints;
 #endif
 	int			NamedLWLockTrancheRequests;
-	char	  **NamedLWLockTrancheNames;
+	NamedLWLockTranche *NamedLWLockTrancheNames;
 	LWLockPadded *MainLWLockArray;
 	slock_t    *ProcStructLock;
 	PROC_HDR   *ProcGlobal;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 31a4133a1df..5cae49ea817 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -146,12 +146,12 @@ StaticAssertDecl(lengthof(BuiltinTrancheNames) ==
 
 /*
  * This is indexed by tranche ID minus LWTRANCHE_FIRST_USER_DEFINED, and
- * points to the shared memory locations of the names of all
+ * points to the shared memory locations of the names and number of locks of all
  * dynamically-created tranches.  Backends inherit the pointer by fork from the
  * postmaster (except in the EXEC_BACKEND case, where we have special measures
  * to pass it down).
  */
-char	  **NamedLWLockTrancheNames = NULL;
+NamedLWLockTranche *NamedLWLockTrancheNames = NULL;
 
 /*
  * This points to the main array of LWLocks in shared memory.  Backends inherit
@@ -202,6 +202,7 @@ static void InitializeLWLocks(void);
 static inline void LWLockReportWaitStart(LWLock *lock);
 static inline void LWLockReportWaitEnd(void);
 static const char *GetLWTrancheName(uint16 trancheId);
+static int	LWLockNewTrancheIdInternal(const char *tranche_name, int num_lwlocks);
 
 #define T_NAME(lock) \
 	GetLWTrancheName((lock)->tranche)
@@ -404,8 +405,7 @@ LWLockShmemSize(void)
 	size = add_size(size, sizeof(int) + LWLOCK_PADDED_SIZE);
 
 	/* space for named tranches. */
-	size = add_size(size, mul_size(MAX_NAMED_TRANCHES, sizeof(char *)));
-	size = add_size(size, mul_size(MAX_NAMED_TRANCHES, NAMEDATALEN));
+	size = add_size(size, mul_size(MAX_NAMED_TRANCHES, sizeof(NamedLWLockTranche)));
 
 	return size;
 }
@@ -426,15 +426,6 @@ CreateLWLocks(void)
 		/* Allocate space */
 		ptr = (char *) ShmemAlloc(spaceLocks);
 
-		/* Initialize tranche names */
-		NamedLWLockTrancheNames = (char **) ptr;
-		ptr += MAX_NAMED_TRANCHES * sizeof(char *);
-		for (int i = 0; i < MAX_NAMED_TRANCHES; i++)
-		{
-			NamedLWLockTrancheNames[i] = ptr;
-			ptr += NAMEDATALEN;
-		}
-
 		/* Leave room for dynamic allocation of tranches */
 		ptr += sizeof(int);
 
@@ -461,6 +452,7 @@ CreateLWLocks(void)
 static void
 InitializeLWLocks(void)
 {
+	int			numNamedLocks = NumLWLocksForNamedTranches();
 	int			id;
 	int			i;
 	int			j;
@@ -485,9 +477,12 @@ InitializeLWLocks(void)
 	for (id = 0; id < NUM_PREDICATELOCK_PARTITIONS; id++, lock++)
 		LWLockInitialize(&lock->lock, LWTRANCHE_PREDICATE_LOCK_MANAGER);
 
+	NamedLWLockTrancheNames = (NamedLWLockTranche *)
+		&MainLWLockArray[NUM_FIXED_LWLOCKS + numNamedLocks];
+
 	/*
-	 * Copy the info about any named tranches into shared memory (so that
-	 * other processes can see it), and initialize the requested LWLocks.
+	 * Allocate a tranche ID in shared memory, and initialize the requested
+	 * LWLocks.
 	 */
 	if (NamedLWLockTrancheRequests > 0)
 	{
@@ -499,7 +494,7 @@ InitializeLWLocks(void)
 			int			tranche;
 
 			request = &NamedLWLockTrancheRequestArray[i];
-			tranche = LWLockNewTrancheId(request->tranche_name);
+			tranche = LWLockNewTrancheIdInternal(request->tranche_name, request->num_lwlocks);
 
 			for (j = 0; j < request->num_lwlocks; j++, lock++)
 				LWLockInitialize(&lock->lock, tranche);
@@ -540,11 +535,11 @@ GetNamedLWLockTranche(const char *tranche_name)
 	lock_pos = NUM_FIXED_LWLOCKS;
 	for (i = 0; i < NamedLWLockTrancheRequests; i++)
 	{
-		if (strcmp(NamedLWLockTrancheRequestArray[i].tranche_name,
+		if (strcmp(NamedLWLockTrancheNames[i].trancheName,
 				   tranche_name) == 0)
 			return &MainLWLockArray[lock_pos];
 
-		lock_pos += NamedLWLockTrancheRequestArray[i].num_lwlocks;
+		lock_pos += NamedLWLockTrancheNames[i].num_lwlocks;
 	}
 
 	elog(ERROR, "requested tranche is not registered");
@@ -554,13 +549,15 @@ GetNamedLWLockTranche(const char *tranche_name)
 }
 
 /*
- * Allocate a new tranche ID with the provided name.
+ * Workhorse for allocating a new tranche with the specified
+ * number of lwlocks.
  */
-int
-LWLockNewTrancheId(const char *tranche_name)
+static int
+LWLockNewTrancheIdInternal(const char *tranche_name, int num_lwlocks)
 {
 	int			result;
 	int		   *LWLockCounter;
+	int			index;
 
 	if (!tranche_name)
 		ereport(ERROR,
@@ -589,13 +586,25 @@ LWLockNewTrancheId(const char *tranche_name)
 	}
 
 	result = LocalLWLockCounter = (*LWLockCounter)++;
-	strlcpy(NamedLWLockTrancheNames[result - LWTRANCHE_FIRST_USER_DEFINED], tranche_name, NAMEDATALEN);
+	index = result - LWTRANCHE_FIRST_USER_DEFINED;
+
+	strlcpy(NamedLWLockTrancheNames[index].trancheName, tranche_name, NAMEDATALEN);
+	NamedLWLockTrancheNames[index].num_lwlocks = num_lwlocks;
 
 	SpinLockRelease(ShmemLock);
 
 	return result;
 }
 
+/*
+ * Allocate a new tranche ID with the provided name.
+ */
+int
+LWLockNewTrancheId(const char *tranche_name)
+{
+	return LWLockNewTrancheIdInternal(tranche_name, 0);
+}
+
 /*
  * RequestNamedLWLockTranche
  *		Request that extra LWLocks be allocated during postmaster
@@ -718,7 +727,7 @@ GetLWTrancheName(uint16 trancheId)
 	 */
 	trancheId -= LWTRANCHE_FIRST_USER_DEFINED;
 
-	return NamedLWLockTrancheNames[trancheId];
+	return NamedLWLockTrancheNames[trancheId].trancheName;
 }
 
 /*
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 9f9c4c7b5ca..eb5b5ca65ed 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -71,9 +71,15 @@ typedef union LWLockPadded
 	char		pad[LWLOCK_PADDED_SIZE];
 } LWLockPadded;
 
+typedef struct NamedLWLockTranche
+{
+	char		trancheName[NAMEDATALEN];
+	int			num_lwlocks;
+} NamedLWLockTranche;
+
 extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
 
-extern PGDLLIMPORT char **NamedLWLockTrancheNames;
+extern PGDLLIMPORT NamedLWLockTranche *NamedLWLockTrancheNames;
 extern PGDLLIMPORT int NamedLWLockTrancheRequests;
 
 /*
-- 
2.39.5 (Apple Git-154)

