summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/ctypes/test/test_parameters.py21
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2017-08-31-17-52-56.bpo-31311.bNE2l-.rst2
-rw-r--r--Modules/_ctypes/_ctypes.c10
3 files changed, 33 insertions, 0 deletions
diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py
index 4eaa15a..e4c25fd 100644
--- a/Lib/ctypes/test/test_parameters.py
+++ b/Lib/ctypes/test/test_parameters.py
@@ -1,5 +1,6 @@
import unittest
from ctypes.test import need_symbol
+import test.support
class SimpleTypesTestCase(unittest.TestCase):
@@ -180,6 +181,26 @@ class SimpleTypesTestCase(unittest.TestCase):
self.assertRaises(TypeError, _Pointer.from_param, 42)
self.assertRaises(TypeError, _SimpleCData.from_param, 42)
+ @test.support.cpython_only
+ def test_issue31311(self):
+ # __setstate__ should neither raise a SystemError nor crash in case
+ # of a bad __dict__.
+ from ctypes import Structure
+
+ class BadStruct(Structure):
+ @property
+ def __dict__(self):
+ pass
+ with self.assertRaises(TypeError):
+ BadStruct().__setstate__({}, b'foo')
+
+ class WorseStruct(Structure):
+ @property
+ def __dict__(self):
+ 1/0
+ with self.assertRaises(ZeroDivisionError):
+ WorseStruct().__setstate__({}, b'foo')
+
################################################################
if __name__ == '__main__':
diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-08-31-17-52-56.bpo-31311.bNE2l-.rst b/Misc/NEWS.d/next/Core and Builtins/2017-08-31-17-52-56.bpo-31311.bNE2l-.rst
new file mode 100644
index 0000000..db51cd2
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2017-08-31-17-52-56.bpo-31311.bNE2l-.rst
@@ -0,0 +1,2 @@
+Fix a crash in the ``__setstate__()`` method of `ctypes._CData`, in case of
+a bad ``__dict__``. Patch by Oren Milman.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 8afb8cc..eaaedfa 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -2674,6 +2674,16 @@ PyCData_setstate(PyObject *myself, PyObject *args)
len = self->b_size;
memmove(self->b_ptr, data, len);
mydict = PyObject_GetAttrString(myself, "__dict__");
+ if (mydict == NULL) {
+ return NULL;
+ }
+ if (!PyDict_Check(mydict)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s.__dict__ must be a dictionary, not %.200s",
+ Py_TYPE(myself)->tp_name, Py_TYPE(mydict)->tp_name);
+ Py_DECREF(mydict);
+ return NULL;
+ }
res = PyDict_Update(mydict, dict);
Py_DECREF(mydict);
if (res == -1)