mirror of
https://github.com/python/cpython.git
synced 2025-08-30 13:38:43 +00:00
[3.13] gh-117657: Fix race involving immortalizing objects (GH-119927) (#120005)
The free-threaded build currently immortalizes objects that use deferred
reference counting (see gh-117783). This typically happens once the
first non-main thread is created, but the behavior can be suppressed for
tests, in subinterpreters, or during a compile() call.
This fixes a race condition involving the tracking of whether the
behavior is suppressed.
(cherry picked from commit 47fb4327b5
)
This commit is contained in:
parent
ca37034baa
commit
ae705319fc
9 changed files with 30 additions and 44 deletions
|
@ -870,15 +870,15 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
|
|||
// gh-118527: Disable immortalization of code constants for explicit
|
||||
// compile() calls to get consistent frozen outputs between the default
|
||||
// and free-threaded builds.
|
||||
// Subtract two to suppress immortalization (so that 1 -> -1)
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
int old_value = interp->gc.immortalize.enable_on_thread_created;
|
||||
interp->gc.immortalize.enable_on_thread_created = 0;
|
||||
_Py_atomic_add_int(&interp->gc.immortalize, -2);
|
||||
#endif
|
||||
|
||||
result = Py_CompileStringObject(str, filename, start[compile_mode], &cf, optimize);
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
interp->gc.immortalize.enable_on_thread_created = old_value;
|
||||
_Py_atomic_add_int(&interp->gc.immortalize, 2);
|
||||
#endif
|
||||
|
||||
Py_XDECREF(source_copy);
|
||||
|
|
|
@ -703,11 +703,9 @@ _PyGC_Init(PyInterpreterState *interp)
|
|||
{
|
||||
GCState *gcstate = &interp->gc;
|
||||
|
||||
if (_Py_IsMainInterpreter(interp)) {
|
||||
// gh-117783: immortalize objects that would use deferred refcounting
|
||||
// once the first non-main thread is created.
|
||||
gcstate->immortalize.enable_on_thread_created = 1;
|
||||
}
|
||||
// gh-117783: immortalize objects that would use deferred refcounting
|
||||
// once the first non-main thread is created (but not in subinterpreters).
|
||||
gcstate->immortalize = _Py_IsMainInterpreter(interp) ? 0 : -1;
|
||||
|
||||
gcstate->garbage = PyList_New(0);
|
||||
if (gcstate->garbage == NULL) {
|
||||
|
@ -1808,8 +1806,10 @@ _PyGC_ImmortalizeDeferredObjects(PyInterpreterState *interp)
|
|||
{
|
||||
struct visitor_args args;
|
||||
_PyEval_StopTheWorld(interp);
|
||||
gc_visit_heaps(interp, &immortalize_visitor, &args);
|
||||
interp->gc.immortalize.enabled = 1;
|
||||
if (interp->gc.immortalize == 0) {
|
||||
gc_visit_heaps(interp, &immortalize_visitor, &args);
|
||||
interp->gc.immortalize = 1;
|
||||
}
|
||||
_PyEval_StartTheWorld(interp);
|
||||
}
|
||||
|
||||
|
|
|
@ -1583,9 +1583,7 @@ new_threadstate(PyInterpreterState *interp, int whence)
|
|||
}
|
||||
else {
|
||||
#ifdef Py_GIL_DISABLED
|
||||
if (interp->gc.immortalize.enable_on_thread_created &&
|
||||
!interp->gc.immortalize.enabled)
|
||||
{
|
||||
if (_Py_atomic_load_int(&interp->gc.immortalize) == 0) {
|
||||
// Immortalize objects marked as using deferred reference counting
|
||||
// the first time a non-main thread is created.
|
||||
_PyGC_ImmortalizeDeferredObjects(interp);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue