diff options
author | Vinay Sajip <vinay_sajip@yahoo.co.uk> | 2019-10-31 08:03:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-31 08:03:54 (GMT) |
commit | 79d4ed102a5069c6cebaed2627cb1645637f0429 (patch) | |
tree | d163eaefd7890bff55c1ca81d9666705634c79b3 /Modules | |
parent | bdac32e9fe25fdb97a7172a93aabd1ffead89462 (diff) | |
download | cpython-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.c | 24 | ||||
-rw-r--r-- | Modules/_ctypes/_ctypes_test.c | 63 | ||||
-rw-r--r-- | Modules/_ctypes/ctypes.h | 2 | ||||
-rw-r--r-- | Modules/_ctypes/stgdict.c | 9 |
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: |