Skip to content

Commit 57c2561

Browse files
orenmnserhiy-storchaka
authored andcommitted
bpo-31311: Fix a SystemError and a crash in ctypes._CData.__setstate__(), in case of a bad __dict__. (#3254)
1 parent 0d4497b commit 57c2561

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

‎Lib/ctypes/test/test_parameters.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import unittest
22
from ctypes.test import need_symbol
3+
import test.support
34

45
class SimpleTypesTestCase(unittest.TestCase):
56

@@ -180,6 +181,26 @@ def test_abstract(self):
180181
self.assertRaises(TypeError, _Pointer.from_param, 42)
181182
self.assertRaises(TypeError, _SimpleCData.from_param, 42)
182183

184+
@test.support.cpython_only
185+
def test_issue31311(self):
186+
# __setstate__ should neither raise a SystemError nor crash in case
187+
# of a bad __dict__.
188+
from ctypes import Structure
189+
190+
class BadStruct(Structure):
191+
@property
192+
def __dict__(self):
193+
pass
194+
with self.assertRaises(TypeError):
195+
BadStruct().__setstate__({}, b'foo')
196+
197+
class WorseStruct(Structure):
198+
@property
199+
def __dict__(self):
200+
1/0
201+
with self.assertRaises(ZeroDivisionError):
202+
WorseStruct().__setstate__({}, b'foo')
203+
183204
################################################################
184205

185206
if __name__ == '__main__':
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash in the ``__setstate__()`` method of `ctypes._CData`, in case of
2+
a bad ``__dict__``. Patch by Oren Milman.

‎Modules/_ctypes/_ctypes.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2674,6 +2674,16 @@ PyCData_setstate(PyObject *myself, PyObject *args)
26742674
len = self->b_size;
26752675
memmove(self->b_ptr, data, len);
26762676
mydict = PyObject_GetAttrString(myself, "__dict__");
2677+
if (mydict == NULL) {
2678+
return NULL;
2679+
}
2680+
if (!PyDict_Check(mydict)) {
2681+
PyErr_Format(PyExc_TypeError,
2682+
"%.200s.__dict__ must be a dictionary, not %.200s",
2683+
Py_TYPE(myself)->tp_name, Py_TYPE(mydict)->tp_name);
2684+
Py_DECREF(mydict);
2685+
return NULL;
2686+
}
26772687
res = PyDict_Update(mydict, dict);
26782688
Py_DECREF(mydict);
26792689
if (res == -1)

0 commit comments

Comments
 (0)