summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 0f5ebc6..d8f5f6d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -992,6 +992,7 @@ static void
set_version_unlocked(PyTypeObject *tp, unsigned int version)
{
ASSERT_TYPE_LOCK_HELD();
+ assert(version == 0 || (tp->tp_versions_used != _Py_ATTR_CACHE_UNUSED));
#ifndef Py_GIL_DISABLED
PyInterpreterState *interp = _PyInterpreterState_GET();
// lookup the old version and set to null
@@ -1148,6 +1149,10 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
PyObject *b = PyTuple_GET_ITEM(bases, i);
PyTypeObject *cls = _PyType_CAST(b);
+ if (cls->tp_versions_used >= _Py_ATTR_CACHE_UNUSED) {
+ goto clear;
+ }
+
if (!is_subtype_with_mro(lookup_tp_mro(type), type, cls)) {
goto clear;
}
@@ -1156,7 +1161,8 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
clear:
assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
- set_version_unlocked(type, 0); /* 0 is not a valid version tag */
+ set_version_unlocked(type, 0); /* 0 is not a valid version tag */
+ type->tp_versions_used = _Py_ATTR_CACHE_UNUSED;
if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
// This field *must* be invalidated if the type is modified (see the
// comment on struct _specialization_cache):
@@ -1208,6 +1214,9 @@ _PyType_GetVersionForCurrentState(PyTypeObject *tp)
#define MAX_VERSIONS_PER_CLASS 1000
+#if _Py_ATTR_CACHE_UNUSED < MAX_VERSIONS_PER_CLASS
+#error "_Py_ATTR_CACHE_UNUSED must be bigger than max"
+#endif
static int
assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
@@ -1225,6 +1234,7 @@ assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
return 0;
}
if (type->tp_versions_used >= MAX_VERSIONS_PER_CLASS) {
+ /* (this includes `tp_versions_used == _Py_ATTR_CACHE_UNUSED`) */
return 0;
}