https://github.com/python/cpython/commit/3387b193b1a1f58d9f6efc9ae8890db457f4cc54
commit: 3387b193b1a1f58d9f6efc9ae8890db457f4cc54
branch: main
author: Gregory P. Smith <[email protected]>
committer: gpshead <[email protected]>
date: 2026-10-22T22:59:51-07:00
summary:
gh-160326: Raise ValueError for a NaN timeout in Condition.wait() (GH-160327)
A NaN timeout was treated as zero, which made the deadline loops built
on Condition.wait(), such as Queue.get() and Semaphore.acquire(), spin
without ever timing out.
files:
A Misc/NEWS.d/next/Library/2026-10-22-18-30-00.gh-issue-160326.nAn7Tq.rst
M Lib/test/lock_tests.py
M Lib/threading.py
diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
index 691029a1a54f7f..47025c041daf1e 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -562,6 +562,10 @@ def f():
for r, dt in results2:
self.assertTrue(r)
+ def test_nan_timeout(self):
+ evt = self.eventtype()
+ self.assertRaises(ValueError, evt.wait, float('nan'))
+
def test_set_and_clear(self):
# gh-57711: check that wait() returns true even when the event is
# cleared before the waiting thread is woken up.
@@ -760,6 +764,14 @@ def f():
# In practice, this implementation has no spurious wakeups.
self.assertFalse(result)
+ def test_nan_timeout(self):
+ cond = self.condtype()
+ nan = float('nan')
+ with cond:
+ self.assertRaises(ValueError, cond.wait, nan)
+ self.assertRaises(ValueError, cond.wait_for, lambda: False, nan)
+ self.assertEqual(len(cond._waiters), 0)
+
def test_waitfor(self):
cond = self.condtype()
state = 0
diff --git a/Lib/threading.py b/Lib/threading.py
index abac31e25886fa..507d40a1baa275 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -363,10 +363,11 @@ def wait(self, timeout=None):
waiter.acquire()
gotit = True
else:
- if timeout > 0:
- gotit = waiter.acquire(True, timeout)
- else:
+ if timeout <= 0:
gotit = waiter.acquire(False)
+ else:
+ # A NaN timeout is rejected by acquire().
+ gotit = waiter.acquire(True, timeout)
return gotit
finally:
self._acquire_restore(saved_state)
diff --git
a/Misc/NEWS.d/next/Library/2026-10-22-18-30-00.gh-issue-160326.nAn7Tq.rst
b/Misc/NEWS.d/next/Library/2026-10-22-18-30-00.gh-issue-160326.nAn7Tq.rst
new file mode 100644
index 00000000000000..4349a7380c377d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-22-18-30-00.gh-issue-160326.nAn7Tq.rst
@@ -0,0 +1,5 @@
+Raise :exc:`ValueError` for a NaN *timeout* in
+:meth:`threading.Condition.wait` and the blocking calls built on it, such as
+:meth:`threading.Event.wait`, :meth:`threading.Semaphore.acquire` and
+:meth:`queue.Queue.get`, instead of returning at once or looping without ever
+timing out.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]