diff --git a/Include/cpython/funcobject.h b/Include/cpython/funcobject.h index 9e1599a7648564..5e8f3c6e7f0c8a 100644 --- a/Include/cpython/funcobject.h +++ b/Include/cpython/funcobject.h @@ -88,10 +88,14 @@ PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); /* Static inline functions for direct access to these values. Type checks are *not* done, so use with care. */ static inline PyObject* PyFunction_GET_CODE(PyObject *func) { - return _PyFunction_CAST(func)->func_code; + PyFunctionObject *op = _PyFunction_CAST(func); +#ifdef Py_GIL_DISABLED + return (PyObject *)_Py_atomic_load_ptr(&op->func_code); +#else + return op->func_code; +#endif } #define PyFunction_GET_CODE(func) PyFunction_GET_CODE(_PyObject_CAST(func)) - static inline PyObject* PyFunction_GET_GLOBALS(PyObject *func) { return _PyFunction_CAST(func)->func_globals; } diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-12-01-44.gh-issue-145272.MeSSbg.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-12-01-44.gh-issue-145272.MeSSbg.rst new file mode 100644 index 00000000000000..74ba9e58892827 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-12-01-44.gh-issue-145272.MeSSbg.rst @@ -0,0 +1 @@ +Fixing race condition in PyFunctionObject.func_code diff --git a/Objects/funcobject.c b/Objects/funcobject.c index efe27a2b70c4de..a77de332ac6ec5 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -631,7 +631,8 @@ func_get_code(PyObject *self, void *Py_UNUSED(ignored)) return NULL; } - return Py_NewRef(op->func_code); + PyCodeObject *code = _Py_atomic_load_ptr(&op->func_code); + return Py_NewRef(code); } static int @@ -664,7 +665,7 @@ func_set_code(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) return -1; } - PyObject *func_code = PyFunction_GET_CODE(op); + PyCodeObject *func_code = (PyCodeObject *)PyFunction_GET_CODE(op); int old_flags = ((PyCodeObject *)func_code)->co_flags; int new_flags = ((PyCodeObject *)value)->co_flags; int mask = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR; @@ -679,7 +680,10 @@ func_set_code(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) handle_func_event(PyFunction_EVENT_MODIFY_CODE, op, value); _PyFunction_ClearVersion(op); - Py_XSETREF(op->func_code, Py_NewRef(value)); + PyCodeObject *new = (PyCodeObject *)Py_NewRef(value); + PyCodeObject *old = + (PyCodeObject *)_Py_atomic_exchange_ptr(&op->func_code, new); + Py_XDECREF(old); return 0; }