Skip to content

Commit 85dabb9

Browse files
authored
[3.14] gh-137238: Fix data race in _Py_slot_tp_getattr_hook (gh-137240) (#137416)
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 485b16b)
1 parent 5cd6cfe commit 85dabb9

File tree

3 files changed

+4
-9
lines changed

3 files changed

+4
-9
lines changed

Objects/typeobject.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10278,7 +10278,10 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
1027810278
getattr = _PyType_LookupRef(tp, &_Py_ID(__getattr__));
1027910279
if (getattr == NULL) {
1028010280
/* No __getattr__ hook: use a simpler dispatcher */
10281+
#ifndef Py_GIL_DISABLED
10282+
// Replacing the slot is only thread-safe if there is a GIL.
1028110283
tp->tp_getattro = _Py_slot_tp_getattro;
10284+
#endif
1028210285
return _Py_slot_tp_getattro(self, name);
1028310286
}
1028410287
/* speed hack: we could use lookup_maybe, but that would resolve the

Python/specialize.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -935,8 +935,7 @@ analyze_descriptor_load(PyTypeObject *type, PyObject *name, PyObject **descr, un
935935
PyObject *getattr = _PyType_Lookup(type, &_Py_ID(__getattr__));
936936
has_getattr = getattr != NULL;
937937
if (has_custom_getattribute) {
938-
if (getattro_slot == _Py_slot_tp_getattro &&
939-
!has_getattr &&
938+
if (!has_getattr &&
940939
Py_IS_TYPE(getattribute, &PyFunction_Type)) {
941940
*descr = getattribute;
942941
*tp_version = ga_version;
@@ -1259,12 +1258,6 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
12591258
return -1;
12601259
case GETATTRIBUTE_IS_PYTHON_FUNCTION:
12611260
{
1262-
#ifndef Py_GIL_DISABLED
1263-
// In free-threaded builds it's possible for tp_getattro to change
1264-
// after the call to analyze_descriptor. That is fine: the version
1265-
// guard will fail.
1266-
assert(type->tp_getattro == _Py_slot_tp_getattro);
1267-
#endif
12681261
assert(Py_IS_TYPE(descr, &PyFunction_Type));
12691262
_PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
12701263
if (!function_check_args(descr, 2, LOAD_ATTR)) {

Tools/tsan/suppressions_free_threading.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ race:PyObject_Realloc
5050

5151
# gh-133467. Some of these could be hard to trigger.
5252
race_top:update_one_slot
53-
race_top:_Py_slot_tp_getattr_hook
5453
race_top:slot_tp_descr_get
5554
race_top:type_set_name
5655
race_top:set_tp_bases

0 commit comments

Comments
 (0)