summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorPauli Virtanen <pav@iki.fi>2017-08-30 09:40:05 (GMT)
committerAntoine Pitrou <pitrou@free.fr>2017-08-30 09:40:05 (GMT)
commit2d1653aa43cf02e6b74f9d4f178fac9969a293e2 (patch)
tree24c1b3dc7a874baabcb8d81d0fc559b13e72955d /Modules
parent87c50245b1ba21469cc2e4e84cd5e5cd54ff954d (diff)
downloadcpython-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.c69
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);