Skip to content

Commit 81691b0

Browse files
[2.7] bpo-31311: Fix a SystemError and a crash in ctypes._CData.__setstate__(), in case of a bad __dict__. (GH-3254). (#3781)
(cherry picked from commit 57c2561)
1 parent 4954b8d commit 81691b0

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, sys
22
from ctypes.test import need_symbol
3+
import test.support
34

45
class SimpleTypesTestCase(unittest.TestCase):
56

@@ -175,6 +176,26 @@ def from_param(cls, obj):
175176
self.assertRaises(ArgumentError, func, 99)
176177

177178

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

180201
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
@@ -2786,6 +2786,16 @@ PyCData_setstate(PyObject *_self, PyObject *args)
27862786
len = self->b_size;
27872787
memmove(self->b_ptr, data, len);
27882788
mydict = PyObject_GetAttrString(_self, "__dict__");
2789+
if (mydict == NULL) {
2790+
return NULL;
2791+
}
2792+
if (!PyDict_Check(mydict)) {
2793+
PyErr_Format(PyExc_TypeError,
2794+
"%.200s.__dict__ must be a dictionary, not %.200s",
2795+
Py_TYPE(_self)->tp_name, Py_TYPE(mydict)->tp_name);
2796+
Py_DECREF(mydict);
2797+
return NULL;
2798+
}
27892799
res = PyDict_Update(mydict, dict);
27902800
Py_DECREF(mydict);
27912801
if (res == -1)

0 commit comments

Comments
 (0)