From 349f3fa56abda1f9411400ae9a05efabcb2270e8 Mon Sep 17 00:00:00 2001
From: Satya Narlapuram <satyanarlapuram@gmail.com>
Date: Thu, 26 Mar 2026 21:42:15 +0000
Subject: [PATCH] Fix LockHasWaiters() crash for fast-path locks

LockHasWaiters() assumes that the LOCALLOCK's lock and proclock pointers
are populated, but this is not the case for locks acquired via the
fast-path optimization.  Weak relation locks (< ShareUpdateExclusiveLock),
including AccessShareLock, are not stored in the shared lock hash table,
leaving the LOCALLOCK entry with lock = NULL and proclock = NULL.

If LockHasWaiters() is called for such a lock, it dereferences those NULL
pointers when reading proclock->holdMask and lock->waitMask, causing a
segfault.


Fix by checking whether the LOCALLOCK has been populated and, if not,
calling FastPathGetRelationLockEntry() to transfer the lock from the
fast-path arrays into the main lock table.
---
 src/backend/storage/lmgr/lock.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index d930c66c..3f4d343d 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -743,6 +743,17 @@ LockHasWaiters(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 	 */
 	partitionLock = LockHashPartitionLock(locallock->hashcode);
 
+	/*
+	 * If the local lock was taken via the fast-path, we need to move it
+	 * to the primary lock table, or just get a pointer to the existing
+	 * primary lock table entry if by chance it's already been transferred.
+	 */
+	if (locallock->proclock == NULL)
+	{
+		locallock->proclock = FastPathGetRelationLockEntry(locallock);
+		locallock->lock = locallock->proclock->tag.myLock;
+	}
+
 	LWLockAcquire(partitionLock, LW_SHARED);
 
 	/*
-- 
2.43.0

