summaryrefslogtreecommitdiff
path: root/Modules/_ctypes
diff options
context:
space:
mode:
authorVinay Sajip <vinay_sajip@yahoo.co.uk>2016-08-05 21:10:26 +0100
committerVinay Sajip <vinay_sajip@yahoo.co.uk>2016-08-05 21:10:26 +0100
commite1f3afbde2b078598ac6db4ba0d946f289000cc9 (patch)
treebd956cb759e3f35b59c2f689c58cd9f4f5120bdc /Modules/_ctypes
parent3d36f0f712e8a720e66808e2b634aace11c6bb88 (diff)
downloadcpython-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.c18
-rw-r--r--Modules/_ctypes/libffi_msvc/ffi.c14
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++;