From 9d692841691590c25e6cf5b2250a594d3bf54825 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 10 Nov 2022 03:50:34 -0800 Subject: GH-99257: Check the owner's type when specializing slots (GH-99258) --- Lib/test/test_opcache.py | 67 ++++++++++++++++++++++ .../2022-10-21-11-28-53.gh-issue-99257.nmcuf-.rst | 3 + Python/specialize.c | 8 +++ 3 files changed, 78 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-10-21-11-28-53.gh-issue-99257.nmcuf-.rst diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 5c032d5..e39b726 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -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 index 0000000..e8de568 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-21-11-28-53.gh-issue-99257.nmcuf-.rst @@ -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. diff --git a/Python/specialize.c b/Python/specialize.c index 61d7a5d..f845967 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -740,6 +740,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; @@ -849,6 +853,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; -- cgit v0.12