diff options
author | Vinay Sajip <vinay_sajip@yahoo.co.uk> | 2016-08-05 21:10:26 +0100 |
---|---|---|
committer | Vinay Sajip <vinay_sajip@yahoo.co.uk> | 2016-08-05 21:10:26 +0100 |
commit | e1f3afbde2b078598ac6db4ba0d946f289000cc9 (patch) | |
tree | bd956cb759e3f35b59c2f689c58cd9f4f5120bdc /Modules/_ctypes | |
parent | 3d36f0f712e8a720e66808e2b634aace11c6bb88 (diff) | |
download | cpython-git-e1f3afbde2b078598ac6db4ba0d946f289000cc9.tar.gz |
Issue #20160: Handled passing of large structs to callbacks correctly.
Diffstat (limited to 'Modules/_ctypes')
-rw-r--r-- | Modules/_ctypes/_ctypes_test.c | 18 | ||||
-rw-r--r-- | Modules/_ctypes/libffi_msvc/ffi.c | 14 |
2 files changed, 30 insertions, 2 deletions
diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 57628b8993..f295c6fc4c 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -34,6 +34,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 ab6b2209d6..515d802fd8 100644 --- a/Modules/_ctypes/libffi_msvc/ffi.c +++ b/Modules/_ctypes/libffi_msvc/ffi.c @@ -359,7 +359,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; @@ -370,13 +370,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++; |