diff options
author | Pauli Virtanen <pav@iki.fi> | 2017-08-30 09:40:05 (GMT) |
---|---|---|
committer | Antoine Pitrou <pitrou@free.fr> | 2017-08-30 09:40:05 (GMT) |
commit | 2d1653aa43cf02e6b74f9d4f178fac9969a293e2 (patch) | |
tree | 24c1b3dc7a874baabcb8d81d0fc559b13e72955d /Modules | |
parent | 87c50245b1ba21469cc2e4e84cd5e5cd54ff954d (diff) | |
download | cpython-2d1653aa43cf02e6b74f9d4f178fac9969a293e2.zip cpython-2d1653aa43cf02e6b74f9d4f178fac9969a293e2.tar.gz cpython-2d1653aa43cf02e6b74f9d4f178fac9969a293e2.tar.bz2 |
[3.6] bpo-10746: Fix ctypes PEP 3118 type codes for c_long, c_bool, c_int (GH-31) (#3241)
Ctypes currently produces wrong pep3118 type codes for several types.
E.g. memoryview(ctypes.c_long()).format gives "<l" on 64-bit platforms,
but it should be "<q" instead for sizeof(c_long) == 8
The problem is that the '<>' endian specification in the struct syntax
also turns on the "standard size" mode, which makes type characters have
a platform-independent meaning, which does not match with the codes used
internally in ctypes. The struct module format syntax also does not
allow specifying native-size non-native-endian items.
This commit adds a converter function that maps the internal ctypes
codes to appropriate struct module standard-size codes in the pep3118
format strings. The tests are modified to check for this.
(cherry picked from commit 07f1658aa09f6798793c473c72b2951b7fefe220)
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_ctypes/_ctypes.c | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 12234e2..2c01e37 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -250,6 +250,71 @@ PyDict_GetItemProxy(PyObject *dict, PyObject *key) } /******************************************************************/ + +/* + Allocate a memory block for a pep3118 format string, filled with + a suitable PEP 3118 type code corresponding to the given ctypes + type. Returns NULL on failure, with the error indicator set. + + This produces type codes in the standard size mode (cf. struct module), + since the endianness may need to be swapped to a non-native one + later on. + */ +static char * +_ctypes_alloc_format_string_for_type(char code, int big_endian) +{ + char *result; + char pep_code = '\0'; + + switch (code) { +#if SIZEOF_INT == 2 + case 'i': pep_code = 'h'; break; + case 'I': pep_code = 'H'; break; +#elif SIZEOF_INT == 4 + case 'i': pep_code = 'i'; break; + case 'I': pep_code = 'I'; break; +#elif SIZEOF_INT == 8 + case 'i': pep_code = 'q'; break; + case 'I': pep_code = 'Q'; break; +#else +# error SIZEOF_INT has an unexpected value +#endif /* SIZEOF_INT */ +#if SIZEOF_LONG == 4 + case 'l': pep_code = 'l'; break; + case 'L': pep_code = 'L'; break; +#elif SIZEOF_LONG == 8 + case 'l': pep_code = 'q'; break; + case 'L': pep_code = 'Q'; break; +#else +# error SIZEOF_LONG has an unexpected value +#endif /* SIZEOF_LONG */ +#if SIZEOF__BOOL == 1 + case '?': pep_code = '?'; break; +#elif SIZEOF__BOOL == 2 + case '?': pep_code = 'H'; break; +#elif SIZEOF__BOOL == 4 + case '?': pep_code = 'L'; break; +#elif SIZEOF__BOOL == 8 + case '?': pep_code = 'Q'; break; +#else +# error SIZEOF__BOOL has an unexpected value +#endif /* SIZEOF__BOOL */ + default: + /* The standard-size code is the same as the ctypes one */ + pep_code = code; + break; + } + + result = PyMem_Malloc(3); + if (result == NULL) + return NULL; + + result[0] = big_endian ? '>' : '<'; + result[1] = pep_code; + result[2] = '\0'; + return result; +} + /* Allocate a memory block for a pep3118 format string, copy prefix (if non-null) and suffix into it. Returns NULL on failure, with the error @@ -1926,9 +1991,9 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) stgdict->setfunc = fmt->setfunc; stgdict->getfunc = fmt->getfunc; #ifdef WORDS_BIGENDIAN - stgdict->format = _ctypes_alloc_format_string(">", proto_str); + stgdict->format = _ctypes_alloc_format_string_for_type(proto_str[0], 1); #else - stgdict->format = _ctypes_alloc_format_string("<", proto_str); + stgdict->format = _ctypes_alloc_format_string_for_type(proto_str[0], 0); #endif if (stgdict->format == NULL) { Py_DECREF(result); |