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`.
This commit is contained in:
Brett Simmers 2024-03-04 08:29:39 -08:00 committed by GitHub
parent 15dc2979bc
commit 0adfa8482d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 53 additions and 2 deletions

View file

@ -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