Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a0b2568

Browse files
committed
Issue #20160: Merged fix from 3.3.
2 parents c6c2217 + 6f25003 commit a0b2568

3 files changed

Lines changed: 65 additions & 2 deletions

File tree

Lib/ctypes/test/test_callbacks.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import functools
12
import unittest
23
from ctypes import *
34
from ctypes.test import need_symbol
@@ -240,6 +241,40 @@ def callback(a, b, c, d, e):
240241
self.assertEqual(result,
241242
callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5))
242243

244+
def test_callback_large_struct(self):
245+
class Check: pass
246+
247+
class X(Structure):
248+
_fields_ = [
249+
('first', c_ulong),
250+
('second', c_ulong),
251+
('third', c_ulong),
252+
]
253+
254+
def callback(check, s):
255+
check.first = s.first
256+
check.second = s.second
257+
check.third = s.third
258+
259+
check = Check()
260+
s = X()
261+
s.first = 0xdeadbeef
262+
s.second = 0xcafebabe
263+
s.third = 0x0bad1dea
264+
265+
CALLBACK = CFUNCTYPE(None, X)
266+
dll = CDLL(_ctypes_test.__file__)
267+
func = dll._testfunc_cbk_large_struct
268+
func.argtypes = (X, CALLBACK)
269+
func.restype = None
270+
# the function just calls the callback with the passed structure
271+
func(s, CALLBACK(functools.partial(callback, check)))
272+
self.assertEqual(check.first, s.first)
273+
self.assertEqual(check.second, s.second)
274+
self.assertEqual(check.third, s.third)
275+
self.assertEqual(check.first, 0xdeadbeef)
276+
self.assertEqual(check.second, 0xcafebabe)
277+
self.assertEqual(check.third, 0x0bad1dea)
243278

244279
################################################################
245280

Modules/_ctypes/_ctypes_test.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,24 @@ _testfunc_cbk_reg_double(double a, double b, double c, double d, double e,
2626
return func(a*a, b*b, c*c, d*d, e*e);
2727
}
2828

29+
/*
30+
* This structure should be the same as in test_callbacks.py and the
31+
* method test_callback_large_struct. See issues 17310 and 20160: the
32+
* structure must be larger than 8 bytes long.
33+
*/
34+
35+
typedef struct {
36+
unsigned long first;
37+
unsigned long second;
38+
unsigned long third;
39+
} Test;
40+
41+
EXPORT(void)
42+
_testfunc_cbk_large_struct(Test in, void (*func)(Test))
43+
{
44+
func(in);
45+
}
46+
2947
EXPORT(void)testfunc_array(int values[4])
3048
{
3149
printf("testfunc_array %d %d %d %d\n",

Modules/_ctypes/libffi_msvc/ffi.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
359359

360360
if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
361361
*rvalue = *(void **) argp;
362-
argp += 4;
362+
argp += sizeof(void *);
363363
}
364364

365365
p_argv = avalue;
@@ -370,13 +370,23 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
370370

371371
/* Align if necessary */
372372
if ((sizeof(char *) - 1) & (size_t) argp) {
373-
argp = (char *) ALIGN(argp, sizeof(char*));
373+
argp = (char *) ALIGN(argp, sizeof(char*));
374374
}
375375

376376
z = (*p_arg)->size;
377377

378378
/* because we're little endian, this is what it turns into. */
379379

380+
#ifdef _WIN64
381+
if (z > 8) {
382+
/* On Win64, if a single argument takes more than 8 bytes,
383+
* then it is always passed by reference.
384+
*/
385+
*p_argv = *((void**) argp);
386+
z = 8;
387+
}
388+
else
389+
#endif
380390
*p_argv = (void*) argp;
381391

382392
p_argv++;

0 commit comments

Comments
 (0)