[Python-checkins] bpo-28129: fix ctypes crashes (#386) (#3800)
Victor Stinner
webhook-mailer at python.org
Thu Sep 28 10:31:45 EDT 2017
https://github.com/python/cpython/commit/8b83687bdf66d2d10afb78e46bcede399deaefde
commit: 8b83687bdf66d2d10afb78e46bcede399deaefde
branch: 2.7
author: Victor Stinner <victor.stinner at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017年09月28日T07:31:40-07:00
summary:
bpo-28129: fix ctypes crashes (#386) (#3800)
* init commit, with initial tests for from_param and fields __set__ and __get__, and some additions to from_buffer and from_buffer_copy
* added the rest of tests and patches. probably only a first draft.
* removed trailing spaces
* replace ctype with ctypes in error messages
* change back from ctypes instance to ctype instance
(cherry picked from commit 1bea762d9ec823544c530d567330a47f64d93d4f)
files:
M Lib/ctypes/test/test_frombuffer.py
M Lib/ctypes/test/test_funcptr.py
M Lib/ctypes/test/test_parameters.py
M Lib/ctypes/test/test_pointers.py
M Lib/ctypes/test/test_struct_fields.py
M Modules/_ctypes/_ctypes.c
M Modules/_ctypes/cfield.c
diff --git a/Lib/ctypes/test/test_frombuffer.py b/Lib/ctypes/test/test_frombuffer.py
index d708ed6906f..99c32e095b8 100644
--- a/Lib/ctypes/test/test_frombuffer.py
+++ b/Lib/ctypes/test/test_frombuffer.py
@@ -78,12 +78,21 @@ def test_fom_buffer_copy_with_offset(self):
(c_int * 1).from_buffer_copy, a, 16 * sizeof(c_int))
def test_abstract(self):
+ from ctypes import _Pointer, _SimpleCData, _CFuncPtr
+
self.assertRaises(TypeError, Array.from_buffer, bytearray(10))
self.assertRaises(TypeError, Structure.from_buffer, bytearray(10))
self.assertRaises(TypeError, Union.from_buffer, bytearray(10))
+ self.assertRaises(TypeError, _CFuncPtr.from_buffer, bytearray(10))
+ self.assertRaises(TypeError, _Pointer.from_buffer, bytearray(10))
+ self.assertRaises(TypeError, _SimpleCData.from_buffer, bytearray(10))
+
self.assertRaises(TypeError, Array.from_buffer_copy, b"123")
self.assertRaises(TypeError, Structure.from_buffer_copy, b"123")
self.assertRaises(TypeError, Union.from_buffer_copy, b"123")
+ self.assertRaises(TypeError, _CFuncPtr.from_buffer_copy, b"123")
+ self.assertRaises(TypeError, _Pointer.from_buffer_copy, b"123")
+ self.assertRaises(TypeError, _SimpleCData.from_buffer_copy, b"123")
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/ctypes/test/test_funcptr.py b/Lib/ctypes/test/test_funcptr.py
index 58cbb47af49..575030327e0 100644
--- a/Lib/ctypes/test/test_funcptr.py
+++ b/Lib/ctypes/test/test_funcptr.py
@@ -123,5 +123,10 @@ def c_string(init):
self.assertEqual(strtok(None, "\n"), "c")
self.assertEqual(strtok(None, "\n"), None)
+ def test_abstract(self):
+ from ctypes import _CFuncPtr
+
+ self.assertRaises(TypeError, _CFuncPtr, 13, "name", 42, "iid")
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py
index 0cac9069c6c..c6231f706b9 100644
--- a/Lib/ctypes/test/test_parameters.py
+++ b/Lib/ctypes/test/test_parameters.py
@@ -175,6 +175,16 @@ def from_param(cls, obj):
# ArgumentError: argument 1: ValueError: 99
self.assertRaises(ArgumentError, func, 99)
+ def test_abstract(self):
+ from ctypes import (Array, Structure, Union, _Pointer,
+ _SimpleCData, _CFuncPtr)
+
+ self.assertRaises(TypeError, Array.from_param, 42)
+ self.assertRaises(TypeError, Structure.from_param, 42)
+ self.assertRaises(TypeError, Union.from_param, 42)
+ self.assertRaises(TypeError, _CFuncPtr.from_param, 42)
+ self.assertRaises(TypeError, _Pointer.from_param, 42)
+ self.assertRaises(TypeError, _SimpleCData.from_param, 42)
@test.support.cpython_only
def test_issue31311(self):
diff --git a/Lib/ctypes/test/test_pointers.py b/Lib/ctypes/test/test_pointers.py
index 24b0546c89b..4a8887c1dee 100644
--- a/Lib/ctypes/test/test_pointers.py
+++ b/Lib/ctypes/test/test_pointers.py
@@ -210,6 +210,11 @@ def test_pointer_type_str_name(self):
from ctypes import _pointer_type_cache
del _pointer_type_cache[id(P)]
+ def test_abstract(self):
+ from ctypes import _Pointer
+
+ self.assertRaises(TypeError, _Pointer.set_type, 42)
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/ctypes/test/test_struct_fields.py b/Lib/ctypes/test/test_struct_fields.py
index 22eb3b0cd7b..8045cc82679 100644
--- a/Lib/ctypes/test/test_struct_fields.py
+++ b/Lib/ctypes/test/test_struct_fields.py
@@ -46,5 +46,29 @@ class Y(X):
Y._fields_ = []
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
+ # __set__ and __get__ should raise a TypeError in case their self
+ # argument is not a ctype instance.
+ def test___set__(self):
+ class MyCStruct(Structure):
+ _fields_ = (("field", c_int),)
+ self.assertRaises(TypeError,
+ MyCStruct.field.__set__, 'wrong type self', 42)
+
+ class MyCUnion(Union):
+ _fields_ = (("field", c_int),)
+ self.assertRaises(TypeError,
+ MyCUnion.field.__set__, 'wrong type self', 42)
+
+ def test___get__(self):
+ class MyCStruct(Structure):
+ _fields_ = (("field", c_int),)
+ self.assertRaises(TypeError,
+ MyCStruct.field.__get__, 'wrong type self', 42)
+
+ class MyCUnion(Union):
+ _fields_ = (("field", c_int),)
+ self.assertRaises(TypeError,
+ MyCUnion.field.__get__, 'wrong type self', 42)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index fb7e9859db2..25740ed7712 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -1036,6 +1036,7 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (proto) {
StgDictObject *itemdict = PyType_stgdict(proto);
const char *current_format;
+ /* PyCPointerType_SetProto has verified proto has a stgdict. */
assert(itemdict);
/* If itemdict->format is NULL, then this is a pointer to an
incomplete type. We create a generic format string
@@ -1082,7 +1083,11 @@ PyCPointerType_set_type(PyTypeObject *self, PyObject *type)
StgDictObject *dict;
dict = PyType_stgdict((PyObject *)self);
- assert(dict);
+ if (!dict) {
+ PyErr_SetString(PyExc_TypeError,
+ "abstract class");
+ return NULL;
+ }
if (-1 == PyCPointerType_SetProto(dict, type))
return NULL;
@@ -1108,7 +1113,11 @@ PyCPointerType_from_param(PyObject *type, PyObject *value)
}
typedict = PyType_stgdict(type);
- assert(typedict); /* Cannot be NULL for pointer types */
+ if (!typedict) {
+ PyErr_SetString(PyExc_TypeError,
+ "abstract class");
+ return NULL;
+ }
/* If we expect POINTER(<type>), but receive a <type> instance, accept
it by calling byref(<type>).
@@ -2226,7 +2235,11 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
}
dict = PyType_stgdict(type);
- assert(dict);
+ if (!dict) {
+ PyErr_SetString(PyExc_TypeError,
+ "abstract class");
+ return NULL;
+ }
/* I think we can rely on this being a one-character string */
fmt = PyString_AsString(dict->proto);
@@ -3347,7 +3360,11 @@ _validate_paramflags(PyTypeObject *type, PyObject *paramflags)
PyObject *argtypes;
dict = PyType_stgdict((PyObject *)type);
- assert(dict); /* Cannot be NULL. 'type' is a PyCFuncPtr type. */
+ if (!dict) {
+ PyErr_SetString(PyExc_TypeError,
+ "abstract class");
+ return 0;
+ }
argtypes = dict->argtypes;
if (paramflags == NULL || dict->argtypes == NULL)
@@ -5090,7 +5107,7 @@ Pointer_ass_item(PyObject *_self, Py_ssize_t index, PyObject *value)
}
stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL fr pointer instances */
+ assert(stgdict); /* Cannot be NULL for pointer instances */
proto = stgdict->proto;
assert(proto);
@@ -5118,7 +5135,7 @@ Pointer_get_contents(CDataObject *self, void *closure)
}
stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL fr pointer instances */
+ assert(stgdict); /* Cannot be NULL for pointer instances */
return PyCData_FromBaseObj(stgdict->proto,
(PyObject *)self, 0,
*(void **)self->b_ptr);
@@ -5137,7 +5154,7 @@ Pointer_set_contents(CDataObject *self, PyObject *value, void *closure)
return -1;
}
stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL fr pointer instances */
+ assert(stgdict); /* Cannot be NULL for pointer instances */
assert(stgdict->proto);
if (!CDataObject_Check(value)) {
int res = PyObject_IsInstance(value, stgdict->proto);
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index e033cd5fffe..6f632d0a072 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -205,7 +205,11 @@ PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value)
{
CDataObject *dst;
char *ptr;
- assert(CDataObject_Check(inst));
+ if (!CDataObject_Check(inst)) {
+ PyErr_SetString(PyExc_TypeError,
+ "not a ctype instance");
+ return -1;
+ }
dst = (CDataObject *)inst;
ptr = dst->b_ptr + self->offset;
if (value == NULL) {
@@ -225,7 +229,11 @@ PyCField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type)
Py_INCREF(self);
return (PyObject *)self;
}
- assert(CDataObject_Check(inst));
+ if (!CDataObject_Check(inst)) {
+ PyErr_SetString(PyExc_TypeError,
+ "not a ctype instance");
+ return NULL;
+ }
src = (CDataObject *)inst;
return PyCData_get(self->proto, self->getfunc, inst,
self->index, self->size, src->b_ptr + self->offset);
More information about the Python-checkins
mailing list