]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-137238: Fix data race in `_Py_slot_tp_getattr_hook` (gh-137240) (#137416)
authorSam Gross <colesbury@gmail.com>
Tue, 7 Oct 2025 17:36:56 +0000 (13:36 -0400)
committerGitHub <noreply@github.com>
Tue, 7 Oct 2025 17:36:56 +0000 (17:36 +0000)
Replacing the slot isn't thread-safe if the GIL is disabled. Don't
require that the slot has been replaced when specializing.
(cherry picked from commit 485b16b4f7b28cefdfb524c2869d473078e349bf)

Objects/typeobject.c
Python/specialize.c
Tools/tsan/suppressions_free_threading.txt

index ab6ad1fe8b5f912f2f58b1da2da99f520a874a18..06b4998507ce9f35063975c27a9bcdc1dc6a3bb1 100644 (file)
@@ -10278,7 +10278,10 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
     getattr = _PyType_LookupRef(tp, &_Py_ID(__getattr__));
     if (getattr == NULL) {
         /* No __getattr__ hook: use a simpler dispatcher */
+#ifndef Py_GIL_DISABLED
+        // Replacing the slot is only thread-safe if there is a GIL.
         tp->tp_getattro = _Py_slot_tp_getattro;
+#endif
         return _Py_slot_tp_getattro(self, name);
     }
     /* speed hack: we could use lookup_maybe, but that would resolve the
index 545098eb51d422eead835eae74cc145a5da6dfa2..dd00f1cb6b002403f46ba12fb1d1eaf4aaa53521 100644 (file)
@@ -935,8 +935,7 @@ analyze_descriptor_load(PyTypeObject *type, PyObject *name, PyObject **descr, un
         PyObject *getattr = _PyType_Lookup(type, &_Py_ID(__getattr__));
         has_getattr = getattr != NULL;
         if (has_custom_getattribute) {
-            if (getattro_slot == _Py_slot_tp_getattro &&
-                !has_getattr &&
+            if (!has_getattr &&
                 Py_IS_TYPE(getattribute, &PyFunction_Type)) {
                 *descr = getattribute;
                 *tp_version = ga_version;
@@ -1259,12 +1258,6 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
             return -1;
         case GETATTRIBUTE_IS_PYTHON_FUNCTION:
         {
-            #ifndef Py_GIL_DISABLED
-            // In free-threaded builds it's possible for tp_getattro to change
-            // after the call to analyze_descriptor. That is fine: the version
-            // guard will fail.
-            assert(type->tp_getattro == _Py_slot_tp_getattro);
-            #endif
             assert(Py_IS_TYPE(descr, &PyFunction_Type));
             _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
             if (!function_check_args(descr, 2, LOAD_ATTR)) {
index 3230f969436c824339d1b5cd0df484842bb1d86f..580757ddd75033e3532ea98bf159b146c3bd4816 100644 (file)
@@ -50,7 +50,6 @@ race:PyObject_Realloc
 
 # gh-133467.  Some of these could be hard to trigger.
 race_top:update_one_slot
-race_top:_Py_slot_tp_getattr_hook
 race_top:slot_tp_descr_get
 race_top:type_set_name
 race_top:set_tp_bases