From 72cbe648c47c9b8de34908531b08d191539dc902 Mon Sep 17 00:00:00 2001
From: Mark Andrews <marka@isc.org>
Date: Thu, 27 Aug 2020 20:40:08 +1000
Subject: [PATCH] Test if linked while holding the queue lock

WARNING: ThreadSanitizer: data race
  Read of size 8 at 0x000000000001 by thread T1:
    #0 client_shutdown bin/named/client.c:849:6
    #1 dispatch lib/isc/task.c:1157:7
    #2 run lib/isc/task.c:1331:2

  Previous write of size 8 at 0x000000000001 by thread T2 (mutexes: write M1, write M2):
    #0 client_shutdown bin/named/client.c:850:3
    #1 dispatch lib/isc/task.c:1157:7
    #2 run lib/isc/task.c:1331:2
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/72cbe648c47c9b8de34908531b08d191539dc902
---
 bin/named/client.c          |  3 +--
 lib/isc/include/isc/queue.h | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/bin/named/client.c b/bin/named/client.c
index 8b3227ad62..978e4d91b8 100644
--- a/bin/named/client.c
+++ b/bin/named/client.c
@@ -850,8 +850,7 @@ client_shutdown(isc_task_t *task, isc_event_t *event) {
 		client->shutdown_arg = NULL;
 	}
 
-	if (ISC_QLINK_LINKED(client, ilink))
-		ISC_QUEUE_UNLINK(client->manager->inactive, client, ilink);
+	ISC_QUEUE_UNLINKIFLINKED(client->manager->inactive, client, ilink);
 
 	client->newstate = NS_CLIENTSTATE_FREED;
 	client->needshutdown = false;
diff --git a/lib/isc/include/isc/queue.h b/lib/isc/include/isc/queue.h
index d682ba4940..416cefcb5d 100644
--- a/lib/isc/include/isc/queue.h
+++ b/lib/isc/include/isc/queue.h
@@ -154,4 +154,23 @@
 		(elt)->link.next = (elt)->link.prev = (void *)(-1); \
 	} while(0)
 
+#define ISC_QUEUE_UNLINKIFLINKED(queue, elt, link) \
+	do { \
+		LOCK(&(queue).headlock); \
+		LOCK(&(queue).taillock); \
+		if (ISC_QLINK_LINKED(elt, link)) { \
+			if ((elt)->link.prev == NULL) \
+				(queue).head = (elt)->link.next; \
+			else \
+				(elt)->link.prev->link.next = (elt)->link.next; \
+			if ((elt)->link.next == NULL) \
+				(queue).tail = (elt)->link.prev; \
+			else \
+				(elt)->link.next->link.prev = (elt)->link.prev; \
+		} \
+		UNLOCK(&(queue).taillock); \
+		UNLOCK(&(queue).headlock); \
+		(elt)->link.next = (elt)->link.prev = (void *)(-1); \
+	} while(0)
+
 #endif /* ISC_QUEUE_H */
-- 
2.23.0

