Hi,

After hearing from a couple of directions about systems spending too
much time scanning the local lock hash table, I wrote the trivial
patch to put them in a linked list, before learning that people have
considered that before, so I should probably go and read some history
on that and find out why it hasn't been done...

However, I noticed in passing that RemoveLocalLock() accesses
*locallock after removing it from the hash table (in assertion builds
only).  So one question I have is whether it's actually a programming
rule that you can't do that (at most you can compare the pointer
against NULL), or whether it's supposed to be
safe-if-you-know-what-you're-doing, as the existing comments hints.
Here also is a patch that does wipe_mem on removed elements, as
threatened last time this topic came up[1], which reveals the problem.
I'm also not exactly sure why it's only a WARNING if your local lock
table is out of sync, but perhaps that's in the archives too.

[1] 
https://www.postgresql.org/message-id/flat/CAHut%2BPs-pL%2B%2Bf6CJwPx2%2BvUqXuew%3DXt-9Bi-6kCyxn%2BFwi2M7w%40mail.gmail.com
From d267c3c0cb26ea97616ca1184ab13664acb4feb8 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.mu...@gmail.com>
Date: Tue, 11 May 2021 11:11:15 +1200
Subject: [PATCH 1/3] Clobber memory released by HASH_REMOVE.

---
 src/backend/utils/hash/dynahash.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index 6546e3c7c7..b977d0395c 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -102,6 +102,7 @@
 #include "storage/shmem.h"
 #include "storage/spin.h"
 #include "utils/dynahash.h"
+#include "utils/memdebug.h"
 #include "utils/memutils.h"
 
 
@@ -1076,10 +1077,12 @@ hash_search_with_hash_value(HTAB *hashp,
 					SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
 
 				/*
-				 * better hope the caller is synchronizing access to this
-				 * element, because someone else is going to reuse it the next
-				 * time something is added to the table
+				 * Clobber the memory, to find bugs in code that accesses
+				 * it after removing.
 				 */
+#ifdef CLOBBER_FREED_MEMORY
+				wipe_mem(ELEMENTKEY(currBucket), hctl->entrysize);
+#endif
 				return (void *) ELEMENTKEY(currBucket);
 			}
 			return NULL;
-- 
2.30.2

From 1cf44ab0f7bfc9d5221ce19f162b3e07ab42c567 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.mu...@gmail.com>
Date: Tue, 11 May 2021 11:11:37 +1200
Subject: [PATCH 2/3] Don't access a local locks after freeing them.

---
 src/backend/storage/lmgr/lock.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 108b4d9023..8642afc275 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -1390,15 +1390,15 @@ RemoveLocalLock(LOCALLOCK *locallock)
 		SpinLockRelease(&FastPathStrongRelationLocks->mutex);
 	}
 
-	if (!hash_search(LockMethodLocalHash,
-					 (void *) &(locallock->tag),
-					 HASH_REMOVE, NULL))
-		elog(WARNING, "locallock table corrupted");
-
 	/*
 	 * Indicate that the lock is released for certain types of locks
 	 */
 	CheckAndSetLockHeld(locallock, false);
+
+	if (!hash_search(LockMethodLocalHash,
+					 (void *) &(locallock->tag),
+					 HASH_REMOVE, NULL))
+		elog(WARNING, "locallock table corrupted");
 }
 
 /*
-- 
2.30.2

Reply via email to