From 7823cfe0328883cec4179d5b024bbeb99c270f75 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 5 May 2025 06:57:29 +0000
Subject: [PATCH v1] Fix a race condition in ConditionVariableTimedSleep()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

A process could exit ConditionVariableTimedSleep() after detecting a state
change (cv != cv_sleep_target) without being removed from the list.

When ConditionVariableTimedSleep() detects that the process is no longer
in the wait list (could be signaled by ConditionVariableSignal() or
ConditionVariableBroadcast()), it re-adds itself to ensure that we don't miss
any additional wakeup.

The issue is that it could leave ConditionVariableTimedSleep() with cv_sleep_target
set to NULL and the process re-added in the wait list.

If cv_sleep_target is set to NULL then subsequent calls to ConditionVariableCancelSleep()
will return early without removing the process from any list.

This could to an assertion failure when the process later tries to wait on a
condition variable, as ConditionVariablePrepareToSleep() skips cleanup
when cv_sleep_target is NULL, resulting in a process trying to be in two wait
lists simultaneously.

The fix re-assigns cv_sleep_target to cv and then ensures that cv_sleep_target
accurately describes which condition variable we’re prepared to wait on.
---
 src/backend/storage/lmgr/condition_variable.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index 228303e77f7..198c1988919 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -184,6 +184,8 @@ ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 		if (!proclist_contains(&cv->wakeup, MyProcNumber, cvWaitLink))
 		{
 			done = true;
+			if (cv_sleep_target == NULL)
+				cv_sleep_target = cv;
 			proclist_push_tail(&cv->wakeup, MyProcNumber, cvWaitLink);
 		}
 		SpinLockRelease(&cv->mutex);
-- 
2.34.1

