/* bitset of which type-watchers care about this type */
unsigned char tp_watched;
+ uint16_t tp_versions_used;
};
/* This struct is used by the specializer
_clear_type_cache()
+ def test_per_class_limit(self):
+ class C:
+ x = 0
+
+ type_assign_version(C)
+ orig_version = type_get_version(C)
+ for i in range(1001):
+ C.x = i
+ type_assign_version(C)
+
+ new_version = type_get_version(C)
+ self.assertEqual(new_version, 0)
+
@support.cpython_only
class TypeCacheWithSpecializationTests(unittest.TestCase):
--- /dev/null
+Limit the number of versions that a single class can use. Prevents a few
+wayward classes using up all the version numbers.
}
}
+#define MAX_VERSIONS_PER_CLASS 1000
+
static int
assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
{
if (!_PyType_HasFeature(type, Py_TPFLAGS_READY)) {
return 0;
}
-
+ if (type->tp_versions_used >= MAX_VERSIONS_PER_CLASS) {
+ return 0;
+ }
+ type->tp_versions_used++;
if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
/* static types */
if (NEXT_GLOBAL_VERSION_TAG > _Py_MAX_GLOBAL_TYPE_VERSION_TAG) {