Skip to content

Commit 703d9b3

Browse files
committed
pythongh-127266: avoid data races when updating type slots
In the free-threaded build, avoid data races caused by updating type slots or type flags after the type was initially created. For those (typically rare) cases, use the stop-the-world mechanism. Remove the use of atomics when reading or writing type flags. The use of atomics is not sufficient to avoid races (since flags are sometimes read without a lock and without atomics) and are no longer required.
1 parent 42b0b06 commit 703d9b3

File tree

8 files changed

+224
-110
lines changed

8 files changed

+224
-110
lines changed

Include/internal/pycore_interp_structs.h

+3
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,11 @@ struct _Py_interp_cached_objects {
667667

668668
/* object.__reduce__ */
669669
PyObject *objreduce;
670+
#ifndef Py_GIL_DISABLED
671+
/* resolve_slotdups() */
670672
PyObject *type_slots_pname;
671673
pytype_slotdef *type_slots_ptrs[MAX_EQUIV];
674+
#endif
672675

673676
/* TypeVar and related types */
674677
PyTypeObject *generic_type;

Include/internal/pycore_object.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ extern int _PyDict_CheckConsistency(PyObject *mp, int check_content);
313313
// Fast inlined version of PyType_HasFeature()
314314
static inline int
315315
_PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
316-
return ((FT_ATOMIC_LOAD_ULONG_RELAXED(type->tp_flags) & feature) != 0);
316+
return ((type->tp_flags) & feature) != 0;
317317
}
318318

319319
extern void _PyType_InitCache(PyInterpreterState *interp);

Include/internal/pycore_typeobject.h

-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ extern int _PyType_AddMethod(PyTypeObject *, PyMethodDef *);
134134
extern void _PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask,
135135
unsigned long flags);
136136

137-
extern unsigned int _PyType_GetVersionForCurrentState(PyTypeObject *tp);
138137
PyAPI_FUNC(void) _PyType_SetVersion(PyTypeObject *tp, unsigned int version);
139138
PyTypeObject *_PyType_LookupByVersion(unsigned int version);
140139

Include/object.h

+7-5
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,12 @@ given type object has a specified feature.
620620
#define Py_TPFLAGS_HAVE_FINALIZE (1UL << 0)
621621
#define Py_TPFLAGS_HAVE_VERSION_TAG (1UL << 18)
622622

623+
// Flag values for ob_flags (16 bits available, if SIZEOF_VOID_P > 4).
624+
#define _Py_IMMORTAL_FLAGS (1 << 0)
625+
#define _Py_STATICALLY_ALLOCATED_FLAG (1 << 2)
626+
#if defined(Py_GIL_DISABLED) && defined(Py_DEBUG)
627+
#define _Py_TYPE_REVEALED_FLAG (1 << 3)
628+
#endif
623629

624630
#define Py_CONSTANT_NONE 0
625631
#define Py_CONSTANT_FALSE 1
@@ -776,11 +782,7 @@ PyType_HasFeature(PyTypeObject *type, unsigned long feature)
776782
// PyTypeObject is opaque in the limited C API
777783
flags = PyType_GetFlags(type);
778784
#else
779-
# ifdef Py_GIL_DISABLED
780-
flags = _Py_atomic_load_ulong_relaxed(&type->tp_flags);
781-
# else
782-
flags = type->tp_flags;
783-
# endif
785+
flags = type->tp_flags;
784786
#endif
785787
return ((flags & feature) != 0);
786788
}

Include/refcount.h

-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ immortal. The latter should be the only instances that require
1919
cleanup during runtime finalization.
2020
*/
2121

22-
#define _Py_STATICALLY_ALLOCATED_FLAG 4
23-
#define _Py_IMMORTAL_FLAGS 1
24-
2522
#if SIZEOF_VOID_P > 4
2623
/*
2724
In 64+ bit systems, any object whose 32 bit reference count is >= 2**31

0 commit comments

Comments
 (0)