]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] GH-99257: Check the owner's type when specializing slots (GH-99324)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 10 Nov 2022 16:44:49 +0000 (08:44 -0800)
committerGitHub <noreply@github.com>
Thu, 10 Nov 2022 16:44:49 +0000 (08:44 -0800)
(cherry picked from commit 9d692841691590c25e6cf5b2250a594d3bf54825)

Co-authored-by: Brandt Bucher <brandtbucher@microsoft.com>
Lib/test/test_opcache.py
Misc/NEWS.d/next/Core and Builtins/2022-10-21-11-28-53.gh-issue-99257.nmcuf-.rst [new file with mode: 0644]
Python/specialize.c

index 5c032d59b13f162ea03004b00c1635bbae8ffb9f..e39b7260624899e958b839768dcb4c4f7b2aa35f 100644 (file)
@@ -177,6 +177,73 @@ class TestLoadAttrCache(unittest.TestCase):
         for _ in range(1025):
             self.assertFalse(f())
 
+    def test_load_shadowing_slot_should_raise_type_error(self):
+        class Class:
+            __slots__ = ("slot",)
+
+        class Sneaky:
+            __slots__ = ("shadowed",)
+            shadowing = Class.slot
+
+        def f(o):
+            o.shadowing
+
+        o = Sneaky()
+        o.shadowed = 42
+
+        for _ in range(1025):
+            with self.assertRaises(TypeError):
+                f(o)
+
+    def test_store_shadowing_slot_should_raise_type_error(self):
+        class Class:
+            __slots__ = ("slot",)
+
+        class Sneaky:
+            __slots__ = ("shadowed",)
+            shadowing = Class.slot
+
+        def f(o):
+            o.shadowing = 42
+
+        o = Sneaky()
+
+        for _ in range(1025):
+            with self.assertRaises(TypeError):
+                f(o)
+
+    def test_load_borrowed_slot_should_not_crash(self):
+        class Class:
+            __slots__ = ("slot",)
+
+        class Sneaky:
+            borrowed = Class.slot
+
+        def f(o):
+            o.borrowed
+
+        o = Sneaky()
+
+        for _ in range(1025):
+            with self.assertRaises(TypeError):
+                f(o)
+
+    def test_store_borrowed_slot_should_not_crash(self):
+        class Class:
+            __slots__ = ("slot",)
+
+        class Sneaky:
+            borrowed = Class.slot
+
+        def f(o):
+            o.borrowed = 42
+
+        o = Sneaky()
+
+        for _ in range(1025):
+            with self.assertRaises(TypeError):
+                f(o)
+
 
 class TestLoadMethodCache(unittest.TestCase):
     def test_descriptor_added_after_optimization(self):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-21-11-28-53.gh-issue-99257.nmcuf-.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-21-11-28-53.gh-issue-99257.nmcuf-.rst
new file mode 100644 (file)
index 0000000..e8de568
--- /dev/null
@@ -0,0 +1,3 @@
+Fix an issue where member descriptors (such as those for
+:attr:`~object.__slots__`) could behave incorrectly or crash instead of
+raising a :exc:`TypeError` when accessed via an instance of an invalid type.
index b318cb5742faed62979e7678931e765d78f2251e..08ce2f5caa6bd909e455da9cb3b7d03d0af66ab9 100644 (file)
@@ -688,6 +688,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
             PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
             struct PyMemberDef *dmem = member->d_member;
             Py_ssize_t offset = dmem->offset;
+            if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
+                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
+                goto fail;
+            }
             if (dmem->flags & PY_AUDIT_READ) {
                 SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_AUDITED_SLOT);
                 goto fail;
@@ -777,6 +781,10 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
             PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
             struct PyMemberDef *dmem = member->d_member;
             Py_ssize_t offset = dmem->offset;
+            if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
+                SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_EXPECTED_ERROR);
+                goto fail;
+            }
             if (dmem->flags & READONLY) {
                 SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_READ_ONLY);
                 goto fail;