From 07f1658aa09f6798793c473c72b2951b7fefe220 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 28 Aug 2017 14:08:49 +0200 Subject: [PATCH] bpo-10746: Fix ctypes PEP 3118 type codes for c_long, c_bool, c_int (#31) Ctypes currently produces wrong pep3118 type codes for several types. E.g. memoryview(ctypes.c_long()).format gives "' 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. --- Lib/ctypes/test/test_pep3118.py | 83 ++++++++++++------- .../2017-08-28-13-01-05.bpo-10746.nmAvfu.rst | 1 + Modules/_ctypes/_ctypes.c | 69 ++++++++++++++- 3 files changed, 123 insertions(+), 30 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2017-08-28-13-01-05.bpo-10746.nmAvfu.rst diff --git a/Lib/ctypes/test/test_pep3118.py b/Lib/ctypes/test/test_pep3118.py index d68397ea802..f3c0e23e53e 100644 --- a/Lib/ctypes/test/test_pep3118.py +++ b/Lib/ctypes/test/test_pep3118.py @@ -112,6 +112,34 @@ Complete._fields_ = [("a", c_long)] # This table contains format strings as they look on little endian # machines. The test replaces '<' with '>' on big endian machines. # + +# Platform-specific type codes +s_bool = {1: '?', 2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_bool)] +s_short = {2: 'h', 4: 'l', 8: 'q'}[sizeof(c_short)] +s_ushort = {2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_ushort)] +s_int = {2: 'h', 4: 'i', 8: 'q'}[sizeof(c_int)] +s_uint = {2: 'H', 4: 'I', 8: 'Q'}[sizeof(c_uint)] +s_long = {4: 'l', 8: 'q'}[sizeof(c_long)] +s_ulong = {4: 'L', 8: 'Q'}[sizeof(c_ulong)] +s_longlong = "q" +s_ulonglong = "Q" +s_float = "f" +s_double = "d" +s_longdouble = "g" + +# Alias definitions in ctypes/__init__.py +if c_int is c_long: + s_int = s_long +if c_uint is c_ulong: + s_uint = s_ulong +if c_longlong is c_long: + s_longlong = s_long +if c_ulonglong is c_ulong: + s_ulonglong = s_ulong +if c_longdouble is c_double: + s_longdouble = s_double + + native_types = [ # type format shape calc itemsize @@ -120,52 +148,51 @@ native_types = [ (c_char, "l:x:>l:y:}", (), BEPoint), - (LEPoint, "T{l:x:>l:y:}", (), POINTER(BEPoint)), - (POINTER(LEPoint), "&T{l:x:>l:y:}".replace('l', s_long), (), BEPoint), + (LEPoint, "T{l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)), + (POINTER(LEPoint), "&T{' : '<'; + 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 @@ -1930,9 +1995,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);