diff options
author | Vinay Sajip <vinay_sajip@yahoo.co.uk> | 2016-08-05 20:44:52 (GMT) |
---|---|---|
committer | Vinay Sajip <vinay_sajip@yahoo.co.uk> | 2016-08-05 20:44:52 (GMT) |
commit | a9391a45221ae91ab7db5e7a5a1b0a6b636396f0 (patch) | |
tree | 89a7b030afd6d1b6b61b11c51a8944588197b7b3 | |
parent | b6337a11450bafda034c518a8363c5c58d409f7c (diff) | |
parent | 0b588869eefc485532660862520bce885cf12346 (diff) | |
download | cpython-a9391a45221ae91ab7db5e7a5a1b0a6b636396f0.zip cpython-a9391a45221ae91ab7db5e7a5a1b0a6b636396f0.tar.gz cpython-a9391a45221ae91ab7db5e7a5a1b0a6b636396f0.tar.bz2 |
Closes #20160: Merged fix from 3.5.
-rw-r--r-- | Lib/ctypes/test/test_callbacks.py | 35 | ||||
-rw-r--r-- | Modules/_ctypes/_ctypes_test.c | 18 | ||||
-rw-r--r-- | Modules/_ctypes/libffi_msvc/ffi.c | 14 |
3 files changed, 65 insertions, 2 deletions
diff --git a/Lib/ctypes/test/test_callbacks.py b/Lib/ctypes/test/test_callbacks.py index 3824f7c..8eac58f 100644 --- a/Lib/ctypes/test/test_callbacks.py +++ b/Lib/ctypes/test/test_callbacks.py @@ -1,3 +1,4 @@ +import functools import unittest from ctypes import * from ctypes.test import need_symbol @@ -240,6 +241,40 @@ class SampleCallbacksTestCase(unittest.TestCase): self.assertEqual(result, callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5)) + def test_callback_large_struct(self): + class Check: pass + + class X(Structure): + _fields_ = [ + ('first', c_ulong), + ('second', c_ulong), + ('third', c_ulong), + ] + + def callback(check, s): + check.first = s.first + check.second = s.second + check.third = s.third + + check = Check() + s = X() + s.first = 0xdeadbeef + s.second = 0xcafebabe + s.third = 0x0bad1dea + + CALLBACK = CFUNCTYPE(None, X) + dll = CDLL(_ctypes_test.__file__) + func = dll._testfunc_cbk_large_struct + func.argtypes = (X, CALLBACK) + func.restype = None + # the function just calls the callback with the passed structure + func(s, CALLBACK(functools.partial(callback, check))) + self.assertEqual(check.first, s.first) + self.assertEqual(check.second, s.second) + self.assertEqual(check.third, s.third) + self.assertEqual(check.first, 0xdeadbeef) + self.assertEqual(check.second, 0xcafebabe) + self.assertEqual(check.third, 0x0bad1dea) ################################################################ diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index f957e02..3c7f892 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -26,6 +26,24 @@ _testfunc_cbk_reg_double(double a, double b, double c, double d, double e, return func(a*a, b*b, c*c, d*d, e*e); } +/* + * This structure should be the same as in test_callbacks.py and the + * method test_callback_large_struct. See issues 17310 and 20160: the + * structure must be larger than 8 bytes long. + */ + +typedef struct { + unsigned long first; + unsigned long second; + unsigned long third; +} Test; + +EXPORT(void) +_testfunc_cbk_large_struct(Test in, void (*func)(Test)) +{ + func(in); +} + EXPORT(void)testfunc_array(int values[4]) { printf("testfunc_array %d %d %d %d\n", diff --git a/Modules/_ctypes/libffi_msvc/ffi.c b/Modules/_ctypes/libffi_msvc/ffi.c index b7586c7..1d82929 100644 --- a/Modules/_ctypes/libffi_msvc/ffi.c +++ b/Modules/_ctypes/libffi_msvc/ffi.c @@ -378,7 +378,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, if ( cif->rtype->type == FFI_TYPE_STRUCT ) { *rvalue = *(void **) argp; - argp += 4; + argp += sizeof(void *); } p_argv = avalue; @@ -389,13 +389,23 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, /* Align if necessary */ if ((sizeof(char *) - 1) & (size_t) argp) { - argp = (char *) ALIGN(argp, sizeof(char*)); + argp = (char *) ALIGN(argp, sizeof(char*)); } z = (*p_arg)->size; /* because we're little endian, this is what it turns into. */ +#ifdef _WIN64 + if (z > 8) { + /* On Win64, if a single argument takes more than 8 bytes, + * then it is always passed by reference. + */ + *p_argv = *((void**) argp); + z = 8; + } + else +#endif *p_argv = (void*) argp; p_argv++; |