summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVinay Sajip <vinay_sajip@yahoo.co.uk>2019-10-31 08:03:54 (GMT)
committerGitHub <noreply@github.com>2019-10-31 08:03:54 (GMT)
commit79d4ed102a5069c6cebaed2627cb1645637f0429 (patch)
treed163eaefd7890bff55c1ca81d9666705634c79b3 /Modules
parentbdac32e9fe25fdb97a7172a93aabd1ffead89462 (diff)
downloadcpython-79d4ed102a5069c6cebaed2627cb1645637f0429.zip
cpython-79d4ed102a5069c6cebaed2627cb1645637f0429.tar.gz
cpython-79d4ed102a5069c6cebaed2627cb1645637f0429.tar.bz2
bpo-16575: Add checks for unions passed by value to functions. (GH-16799)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_ctypes/_ctypes.c24
-rw-r--r--Modules/_ctypes/_ctypes_test.c63
-rw-r--r--Modules/_ctypes/ctypes.h2
-rw-r--r--Modules/_ctypes/stgdict.c9
4 files changed, 98 insertions, 0 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 16a0cfe..5e22b73 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -504,6 +504,9 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt
Py_DECREF(result);
return NULL;
}
+ if (!isStruct) {
+ dict->flags |= TYPEFLAG_HASUNION;
+ }
/* replace the class dict by our updated stgdict, which holds info
about storage requirements of the instances */
if (-1 == PyDict_Update((PyObject *)dict, result->tp_dict)) {
@@ -2383,6 +2386,27 @@ converters_from_argtypes(PyObject *ob)
for (i = 0; i < nArgs; ++i) {
PyObject *cnv;
PyObject *tp = PyTuple_GET_ITEM(ob, i);
+ StgDictObject *stgdict = PyType_stgdict(tp);
+
+ if (stgdict != NULL) {
+ if (stgdict->flags & TYPEFLAG_HASUNION) {
+ Py_DECREF(converters);
+ Py_DECREF(ob);
+ if (!PyErr_Occurred()) {
+ PyErr_Format(PyExc_TypeError,
+ "item %zd in _argtypes_ passes a union by "
+ "value, which is unsupported.",
+ i + 1);
+ }
+ return NULL;
+ }
+ /*
+ if (stgdict->flags & TYPEFLAG_HASBITFIELD) {
+ printf("found stgdict with bitfield\n");
+ }
+ */
+ }
+
if (_PyObject_LookupAttrId(tp, &PyId_from_param, &cnv) <= 0) {
Py_DECREF(converters);
Py_DECREF(ob);
diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c
index 40da652..49ed820 100644
--- a/Modules/_ctypes/_ctypes_test.c
+++ b/Modules/_ctypes/_ctypes_test.c
@@ -131,6 +131,69 @@ _testfunc_array_in_struct2a(Test3B in)
return result;
}
+typedef union {
+ long a_long;
+ struct {
+ int an_int;
+ int another_int;
+ } a_struct;
+} Test4;
+
+typedef struct {
+ int an_int;
+ struct {
+ int an_int;
+ Test4 a_union;
+ } nested;
+ int another_int;
+} Test5;
+
+EXPORT(long)
+_testfunc_union_by_value1(Test4 in) {
+ long result = in.a_long + in.a_struct.an_int + in.a_struct.another_int;
+
+ /* As the union/struct are passed by value, changes to them shouldn't be
+ * reflected in the caller.
+ */
+ memset(&in, 0, sizeof(in));
+ return result;
+}
+
+EXPORT(long)
+_testfunc_union_by_value2(Test5 in) {
+ long result = in.an_int + in.nested.an_int;
+
+ /* As the union/struct are passed by value, changes to them shouldn't be
+ * reflected in the caller.
+ */
+ memset(&in, 0, sizeof(in));
+ return result;
+}
+
+EXPORT(long)
+_testfunc_union_by_reference1(Test4 *in) {
+ long result = in->a_long;
+
+ memset(in, 0, sizeof(Test4));
+ return result;
+}
+
+EXPORT(long)
+_testfunc_union_by_reference2(Test4 *in) {
+ long result = in->a_struct.an_int + in->a_struct.another_int;
+
+ memset(in, 0, sizeof(Test4));
+ return result;
+}
+
+EXPORT(long)
+_testfunc_union_by_reference3(Test5 *in) {
+ long result = in->an_int + in->nested.an_int + in->another_int;
+
+ memset(in, 0, sizeof(Test5));
+ return result;
+}
+
EXPORT(void)testfunc_array(int values[4])
{
printf("testfunc_array %d %d %d %d\n",
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 5d3b966..e58f852 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -288,6 +288,8 @@ PyObject *_ctypes_callproc(PPROC pProc,
#define TYPEFLAG_ISPOINTER 0x100
#define TYPEFLAG_HASPOINTER 0x200
+#define TYPEFLAG_HASUNION 0x400
+#define TYPEFLAG_HASBITFIELD 0x800
#define DICTFLAG_FINAL 0x1000
diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c
index 97bcf55..1d45ade 100644
--- a/Modules/_ctypes/stgdict.c
+++ b/Modules/_ctypes/stgdict.c
@@ -440,6 +440,13 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
PyMem_Free(stgdict->ffi_type_pointer.elements);
basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base);
+ if (basedict) {
+ stgdict->flags |= (basedict->flags &
+ (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD));
+ }
+ if (!isStruct) {
+ stgdict->flags |= TYPEFLAG_HASUNION;
+ }
if (basedict && !use_broken_old_ctypes_semantics) {
size = offset = basedict->size;
align = basedict->align;
@@ -515,8 +522,10 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer;
if (dict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
stgdict->flags |= TYPEFLAG_HASPOINTER;
+ stgdict->flags |= dict->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
dict->flags |= DICTFLAG_FINAL; /* mark field type final */
if (PyTuple_Size(pair) == 3) { /* bits specified */
+ stgdict->flags |= TYPEFLAG_HASBITFIELD;
switch(dict->ffi_type_pointer.type) {
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16: