[Python-checkins] cpython (2.7): Issue #20160: Handled passing of large structs to callbacks correctly.

vinay.sajip python-checkins at python.org
Fri Aug 5 16:19:07 EDT 2016


https://hg.python.org/cpython/rev/09475e6135d0
changeset:   102543:09475e6135d0
branch:      2.7
parent:      102538:5ab52b5ea4a7
user:        Vinay Sajip <vinay_sajip at yahoo.co.uk>
date:        Fri Aug 05 21:10:26 2016 +0100
summary:
  Issue #20160: Handled passing of large structs to callbacks correctly.

files:
  Lib/ctypes/test/test_callbacks.py |  35 +++++++++++++++++++
  Modules/_ctypes/_ctypes_test.c    |  18 +++++++++
  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
--- 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
@@ -246,6 +247,40 @@
         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
--- a/Modules/_ctypes/_ctypes_test.c
+++ b/Modules/_ctypes/_ctypes_test.c
@@ -34,6 +34,24 @@
     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
--- a/Modules/_ctypes/libffi_msvc/ffi.c
+++ b/Modules/_ctypes/libffi_msvc/ffi.c
@@ -359,7 +359,7 @@
 
   if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
     *rvalue = *(void **) argp;
-    argp += 4;
+    argp += sizeof(void *);
   }
 
   p_argv = avalue;
@@ -370,13 +370,23 @@
 
       /* 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++;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list