From 52395326c677e09284365f831d7b4d9838c3a76a Mon Sep 17 00:00:00 2001 From: Sami Imseih 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)