summaryrefslogtreecommitdiffstats
path: root/Python/thread_nt.h
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-09-30 08:16:51 (GMT)
committerGitHub <noreply@github.com>2021-09-30 08:16:51 (GMT)
commit37b8294d6295ca12553fd7c98778be71d24f4b24 (patch)
tree8d9d17fb410224326246dbb25d762feb9aae6053 /Python/thread_nt.h
parenta1437170039dc2c07e6040d3a8ba8d91434b730d (diff)
downloadcpython-37b8294d6295ca12553fd7c98778be71d24f4b24.zip
cpython-37b8294d6295ca12553fd7c98778be71d24f4b24.tar.gz
cpython-37b8294d6295ca12553fd7c98778be71d24f4b24.tar.bz2
bpo-41710: PyThread_acquire_lock_timed() clamps the timout (GH-28643)
PyThread_acquire_lock_timed() now clamps the timeout into the [_PyTime_MIN; _PyTime_MAX] range (_PyTime_t type) if it is too large, rather than calling Py_FatalError() which aborts the process. PyThread_acquire_lock_timed() no longer uses MICROSECONDS_TO_TIMESPEC() to compute sem_timedwait() argument, but _PyTime_GetSystemClock() and _PyTime_AsTimespec_truncate(). Fix _thread.TIMEOUT_MAX value on Windows: the maximum timeout is 0x7FFFFFFF milliseconds (around 24.9 days), not 0xFFFFFFFF milliseconds (around 49.7 days). Set PY_TIMEOUT_MAX to 0x7FFFFFFF milliseconds, rather than 0xFFFFFFFF milliseconds. Fix PY_TIMEOUT_MAX overflow test: replace (us >= PY_TIMEOUT_MAX) with (us > PY_TIMEOUT_MAX).
Diffstat (limited to 'Python/thread_nt.h')
-rw-r--r--Python/thread_nt.h22
1 files changed, 18 insertions, 4 deletions
diff --git a/Python/thread_nt.h b/Python/thread_nt.h
index f8c098c..0beb3d3 100644
--- a/Python/thread_nt.h
+++ b/Python/thread_nt.h
@@ -292,6 +292,10 @@ PyThread_free_lock(PyThread_type_lock aLock)
FreeNonRecursiveMutex(aLock) ;
}
+// WaitForSingleObject() documentation: "The time-out value needs to be a
+// positive number between 0 and 0x7FFFFFFF." INFINITE is equal to 0xFFFFFFFF.
+const DWORD TIMEOUT_MS_MAX = 0x7FFFFFFF;
+
/*
* Return 1 on success if the lock was acquired
*
@@ -309,10 +313,20 @@ PyThread_acquire_lock_timed(PyThread_type_lock aLock,
if (microseconds >= 0) {
milliseconds = microseconds / 1000;
- if (microseconds % 1000 > 0)
- ++milliseconds;
- if (milliseconds > PY_DWORD_MAX) {
- Py_FatalError("Timeout larger than PY_TIMEOUT_MAX");
+ // Round milliseconds away from zero
+ if (microseconds % 1000 > 0) {
+ milliseconds++;
+ }
+ if (milliseconds > (PY_TIMEOUT_T)TIMEOUT_MS_MAX) {
+ // bpo-41710: PyThread_acquire_lock_timed() cannot report timeout
+ // overflow to the caller, so clamp the timeout to
+ // [0, TIMEOUT_MS_MAX] milliseconds.
+ //
+ // TIMEOUT_MS_MAX milliseconds is around 24.9 days.
+ //
+ // _thread.Lock.acquire() and _thread.RLock.acquire() raise an
+ // OverflowError if microseconds is greater than PY_TIMEOUT_MAX.
+ milliseconds = TIMEOUT_MS_MAX;
}
}
else {