summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinay Sajip <vinay_sajip@yahoo.co.uk>2016-08-05 20:44:15 (GMT)
committerVinay Sajip <vinay_sajip@yahoo.co.uk>2016-08-05 20:44:15 (GMT)
commit0b588869eefc485532660862520bce885cf12346 (patch)
treec68bab4a99ac1f20d3ffd83a48d51d5650c359c0
parentb858af61b9bd2f58de0b6023002e9ce3df82b90d (diff)
parenta0b2568627e061f9dd8a31df665e97fdcf4b531d (diff)
downloadcpython-0b588869eefc485532660862520bce885cf12346.zip
cpython-0b588869eefc485532660862520bce885cf12346.tar.gz
cpython-0b588869eefc485532660862520bce885cf12346.tar.bz2
Issue #20160: Merged fix from 3.4.
-rw-r--r--Lib/ctypes/test/test_callbacks.py35
-rw-r--r--Modules/_ctypes/_ctypes_test.c18
-rw-r--r--Modules/_ctypes/libffi_msvc/ffi.c14
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++;