]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-113462: Limit the number of versions that a single class can use. (GH-114900)
authorMark Shannon <mark@hotpy.org>
Mon, 5 Feb 2024 16:20:54 +0000 (16:20 +0000)
committerGitHub <noreply@github.com>
Mon, 5 Feb 2024 16:20:54 +0000 (16:20 +0000)
Include/cpython/object.h
Lib/test/test_type_cache.py
Misc/NEWS.d/next/Core and Builtins/2024-02-02-05-27-48.gh-issue-113462.VMml8q.rst [new file with mode: 0644]
Objects/typeobject.c

index c93931634fee051aeac8d99c923b7f568e49f311..7512bb70c760fdd154515c8bceaf1d60787bda80 100644 (file)
@@ -229,6 +229,7 @@ struct _typeobject {
 
     /* 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
index 295df78a17374a3a6ee5dcac0cdce9a6ea1bf56d..58572c6f4d31578068601de8a37ef13db175dc3b 100644 (file)
@@ -79,6 +79,19 @@ class TypeCacheTests(unittest.TestCase):
 
         _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):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-02-02-05-27-48.gh-issue-113462.VMml8q.rst b/Misc/NEWS.d/next/Core and Builtins/2024-02-02-05-27-48.gh-issue-113462.VMml8q.rst
new file mode 100644 (file)
index 0000000..1a401ec
--- /dev/null
@@ -0,0 +1,2 @@
+Limit the number of versions that a single class can use. Prevents a few
+wayward classes using up all the version numbers.
index a850473cad813dde45782f16c9cba0296cfdbe29..e220d10ce563c29be7af1d419ef561ddd3fab828 100644 (file)
@@ -908,6 +908,8 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
     }
 }
 
+#define MAX_VERSIONS_PER_CLASS 1000
+
 static int
 assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
 {
@@ -922,7 +924,10 @@ 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) {