Skip to content

Commit 9d69284

Browse files
authored
GH-99257: Check the owner's type when specializing slots (GH-99258)
1 parent 26726c7 commit 9d69284

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

Lib/test/test_opcache.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,73 @@ def f():
177177
for _ in range(1025):
178178
self.assertFalse(f())
179179

180+
def test_load_shadowing_slot_should_raise_type_error(self):
181+
class Class:
182+
__slots__ = ("slot",)
183+
184+
class Sneaky:
185+
__slots__ = ("shadowed",)
186+
shadowing = Class.slot
187+
188+
def f(o):
189+
o.shadowing
190+
191+
o = Sneaky()
192+
o.shadowed = 42
193+
194+
for _ in range(1025):
195+
with self.assertRaises(TypeError):
196+
f(o)
197+
198+
def test_store_shadowing_slot_should_raise_type_error(self):
199+
class Class:
200+
__slots__ = ("slot",)
201+
202+
class Sneaky:
203+
__slots__ = ("shadowed",)
204+
shadowing = Class.slot
205+
206+
def f(o):
207+
o.shadowing = 42
208+
209+
o = Sneaky()
210+
211+
for _ in range(1025):
212+
with self.assertRaises(TypeError):
213+
f(o)
214+
215+
def test_load_borrowed_slot_should_not_crash(self):
216+
class Class:
217+
__slots__ = ("slot",)
218+
219+
class Sneaky:
220+
borrowed = Class.slot
221+
222+
def f(o):
223+
o.borrowed
224+
225+
o = Sneaky()
226+
227+
for _ in range(1025):
228+
with self.assertRaises(TypeError):
229+
f(o)
230+
231+
def test_store_borrowed_slot_should_not_crash(self):
232+
class Class:
233+
__slots__ = ("slot",)
234+
235+
class Sneaky:
236+
borrowed = Class.slot
237+
238+
def f(o):
239+
o.borrowed = 42
240+
241+
o = Sneaky()
242+
243+
for _ in range(1025):
244+
with self.assertRaises(TypeError):
245+
f(o)
246+
180247

181248
class TestLoadMethodCache(unittest.TestCase):
182249
def test_descriptor_added_after_optimization(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix an issue where member descriptors (such as those for
2+
:attr:`~object.__slots__`) could behave incorrectly or crash instead of
3+
raising a :exc:`TypeError` when accessed via an instance of an invalid type.

Python/specialize.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
740740
PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
741741
struct PyMemberDef *dmem = member->d_member;
742742
Py_ssize_t offset = dmem->offset;
743+
if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
744+
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
745+
goto fail;
746+
}
743747
if (dmem->flags & PY_AUDIT_READ) {
744748
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_AUDITED_SLOT);
745749
goto fail;
@@ -849,6 +853,10 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
849853
PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
850854
struct PyMemberDef *dmem = member->d_member;
851855
Py_ssize_t offset = dmem->offset;
856+
if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
857+
SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_EXPECTED_ERROR);
858+
goto fail;
859+
}
852860
if (dmem->flags & READONLY) {
853861
SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_READ_ONLY);
854862
goto fail;

0 commit comments

Comments
 (0)