summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorBrett Simmers <swtaarrs@users.noreply.github.com>2024-03-04 16:29:39 (GMT)
committerGitHub <noreply@github.com>2024-03-04 16:29:39 (GMT)
commit0adfa8482d369899e9963206a3307f423309e10c (patch)
treec1f71c0f65b0f01581d37eafa55c26b769915299 /Python
parent15dc2979bc1b24269177f0e150495abb7f3eb546 (diff)
downloadcpython-0adfa8482d369899e9963206a3307f423309e10c.zip
cpython-0adfa8482d369899e9963206a3307f423309e10c.tar.gz
cpython-0adfa8482d369899e9963206a3307f423309e10c.tar.bz2
gh-115832: Fix instrumentation version mismatch during interpreter shutdown (#115856)
A previous commit introduced a bug to `interpreter_clear()`: it set `interp->ceval.instrumentation_version` to 0, without making the corresponding change to `tstate->eval_breaker` (which holds a thread-local copy of the version). After this happens, Python code can still run due to object finalizers during a GC, and the version check in bytecodes.c will see a different result than the one in instrumentation.c causing an infinite loop. The fix itself is straightforward: clear `tstate->eval_breaker` when clearing `interp->ceval.instrumentation_version`.
Diffstat (limited to 'Python')
-rw-r--r--Python/instrumentation.c10
-rw-r--r--Python/pystate.c3
2 files changed, 12 insertions, 1 deletions
diff --git a/Python/instrumentation.c b/Python/instrumentation.c
index 6f1bc2e..018cd66 100644
--- a/Python/instrumentation.c
+++ b/Python/instrumentation.c
@@ -891,8 +891,16 @@ static inline int most_significant_bit(uint8_t bits) {
static uint32_t
global_version(PyInterpreterState *interp)
{
- return (uint32_t)_Py_atomic_load_uintptr_relaxed(
+ uint32_t version = (uint32_t)_Py_atomic_load_uintptr_relaxed(
&interp->ceval.instrumentation_version);
+#ifdef Py_DEBUG
+ PyThreadState *tstate = _PyThreadState_GET();
+ uint32_t thread_version =
+ (uint32_t)(_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
+ ~_PY_EVAL_EVENTS_MASK);
+ assert(thread_version == version);
+#endif
+ return version;
}
/* Atomically set the given version in the given location, without touching
diff --git a/Python/pystate.c b/Python/pystate.c
index a370fff..3d6394f 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -795,7 +795,10 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
Py_CLEAR(interp->audit_hooks);
+ // At this time, all the threads should be cleared so we don't need atomic
+ // operations for instrumentation_version or eval_breaker.
interp->ceval.instrumentation_version = 0;
+ tstate->eval_breaker = 0;
for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) {
interp->monitors.tools[i] = 0;