Skip to content

Commit a6bddb8

Browse files
miss-islingtonserhiy-storchaka
authored andcommitted
[3.6] bpo-31311: Fix a SystemError and a crash in ctypes._CData.__setstate__(), in case of a bad __dict__. (GH-3254) (#3743)
(cherry picked from commit 57c2561)
1 parent e2a30cd commit a6bddb8

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

@@ -170,6 +171,26 @@ def from_param(cls, obj):
170171
self.assertRaises(ArgumentError, func, 99)
171172

172173

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

175196
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
@@ -2663,6 +2663,16 @@ PyCData_setstate(PyObject *myself, PyObject *args)
26632663
len = self->b_size;
26642664
memmove(self->b_ptr, data, len);
26652665
mydict = PyObject_GetAttrString(myself, "__dict__");
2666+
if (mydict == NULL) {
2667+
return NULL;
2668+
}
2669+
if (!PyDict_Check(mydict)) {
2670+
PyErr_Format(PyExc_TypeError,
2671+
"%.200s.__dict__ must be a dictionary, not %.200s",
2672+
Py_TYPE(myself)->tp_name, Py_TYPE(mydict)->tp_name);
2673+
Py_DECREF(mydict);
2674+
return NULL;
2675+
}
26662676
res = PyDict_Update(mydict, dict);
26672677
Py_DECREF(mydict);
26682678
if (res == -1)

0 commit comments

Comments
 (0)