Skip to content

Commit b3badab

Browse files
[3.13] gh-125221: Fix free-threading data race in object.__reduce_ex__ (GH-125267) (#125305)
gh-125221: Fix free-threading data race in `object.__reduce_ex__` (GH-125267) (cherry picked from commit b12e992) Co-authored-by: Sam Gross <colesbury@gmail.com>
1 parent 49f171d commit b3badab

File tree

3 files changed

+15
-15
lines changed

3 files changed

+15
-15
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix possible race condition when calling :meth:`~object.__reduce_ex__` for the
2+
first time in the free threading build.

Objects/object.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,6 +2353,14 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
23532353
}
23542354
}
23552355

2356+
// Cache __reduce__ from PyBaseObject_Type object
2357+
PyObject *baseobj_dict = _PyType_GetDict(&PyBaseObject_Type);
2358+
PyObject *baseobj_reduce = PyDict_GetItemWithError(baseobj_dict, &_Py_ID(__reduce__));
2359+
if (baseobj_reduce == NULL && PyErr_Occurred()) {
2360+
return _PyStatus_ERR("Can't get __reduce__ from base object");
2361+
}
2362+
_Py_INTERP_CACHED_OBJECT(interp, objreduce) = baseobj_reduce;
2363+
23562364
// Must be after static types are initialized
23572365
if (_Py_initialize_generic(interp) < 0) {
23582366
return _PyStatus_ERR("Can't initialize generic types");

Objects/typeobject.c

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7050,18 +7050,7 @@ static PyObject *
70507050
object___reduce_ex___impl(PyObject *self, int protocol)
70517051
/*[clinic end generated code: output=2e157766f6b50094 input=f326b43fb8a4c5ff]*/
70527052
{
7053-
#define objreduce \
7054-
(_Py_INTERP_CACHED_OBJECT(_PyInterpreterState_GET(), objreduce))
7055-
PyObject *reduce, *res;
7056-
7057-
if (objreduce == NULL) {
7058-
PyObject *dict = lookup_tp_dict(&PyBaseObject_Type);
7059-
objreduce = PyDict_GetItemWithError(dict, &_Py_ID(__reduce__));
7060-
if (objreduce == NULL && PyErr_Occurred()) {
7061-
return NULL;
7062-
}
7063-
}
7064-
7053+
PyObject *reduce;
70657054
if (PyObject_GetOptionalAttr(self, &_Py_ID(__reduce__), &reduce) < 0) {
70667055
return NULL;
70677056
}
@@ -7075,10 +7064,12 @@ object___reduce_ex___impl(PyObject *self, int protocol)
70757064
Py_DECREF(reduce);
70767065
return NULL;
70777066
}
7078-
override = (clsreduce != objreduce);
7067+
7068+
PyInterpreterState *interp = _PyInterpreterState_GET();
7069+
override = (clsreduce != _Py_INTERP_CACHED_OBJECT(interp, objreduce));
70797070
Py_DECREF(clsreduce);
70807071
if (override) {
7081-
res = _PyObject_CallNoArgs(reduce);
7072+
PyObject *res = _PyObject_CallNoArgs(reduce);
70827073
Py_DECREF(reduce);
70837074
return res;
70847075
}
@@ -7087,7 +7078,6 @@ object___reduce_ex___impl(PyObject *self, int protocol)
70877078
}
70887079

70897080
return _common_reduce(self, protocol);
7090-
#undef objreduce
70917081
}
70927082

70937083
static PyObject *

0 commit comments

Comments
 (0)