cpython: b701eb69260d (original) (raw)
Mercurial > cpython
changeset 93408:b701eb69260d
Issue #20160: broken ctypes calling convention on MSVC / 64-bit Windows (large structs) Patch by mattip [#20160]
Steve Dower steve.dower@microsoft.com | |
---|---|
date | Wed, 05 Nov 2014 19:30:30 -0800 |
parents | 089573725c77(current diff)cd36ba22602d(diff) |
children | 9ed44777331d |
files | Modules/_ctypes/callproc.c |
diffstat | 6 files changed, 104 insertions(+), 15 deletions(-)[+] [-] Lib/ctypes/test/test_win32.py 26 Modules/_ctypes/_ctypes_test.c 43 Modules/_ctypes/callproc.c 3 Modules/_ctypes/libffi_msvc/ffi.c 29 Modules/_ctypes/libffi_msvc/prep_cif.c 16 Modules/_ctypes/libffi_msvc/types.c 2 |
line wrap: on
line diff
--- a/Lib/ctypes/test/test_win32.py +++ b/Lib/ctypes/test/test_win32.py @@ -111,9 +111,29 @@ class Structures(unittest.TestCase): dll = CDLL(_ctypes_test.file)
pt = POINT(10, 10)[](#l1.7)
rect = RECT(0, 0, 20, 20)[](#l1.8)
self.assertEqual(1, dll.PointInRect(byref(rect), pt))[](#l1.9)
pt = POINT(15, 25)[](#l1.10)
left = c_long.in_dll(dll, 'left')[](#l1.11)
top = c_long.in_dll(dll, 'top')[](#l1.12)
right = c_long.in_dll(dll, 'right')[](#l1.13)
bottom = c_long.in_dll(dll, 'bottom')[](#l1.14)
rect = RECT(left, top, right, bottom)[](#l1.15)
PointInRect = dll.PointInRect[](#l1.16)
PointInRect.argtypes = [POINTER(RECT), POINT][](#l1.17)
self.assertEqual(1, PointInRect(byref(rect), pt))[](#l1.18)
ReturnRect = dll.ReturnRect[](#l1.20)
ReturnRect.argtypes = [c_int, RECT, POINTER(RECT), POINT, RECT,[](#l1.21)
POINTER(RECT), POINT, RECT][](#l1.22)
ReturnRect.restype = RECT[](#l1.23)
for i in range(4):[](#l1.24)
ret = ReturnRect(i, rect, pointer(rect), pt, rect,[](#l1.25)
byref(rect), pt, rect)[](#l1.26)
# the c function will check and modify ret if something is[](#l1.27)
# passed in improperly[](#l1.28)
self.assertEqual(ret.left, left.value)[](#l1.29)
self.assertEqual(ret.right, right.value)[](#l1.30)
self.assertEqual(ret.top, top.value)[](#l1.31)
self.assertEqual(ret.bottom, bottom.value)[](#l1.32)
if name == 'main': unittest.main()
--- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -527,6 +527,49 @@ EXPORT(int) PointInRect(RECT prc, POINT return 1; } +EXPORT(int left = 10); +EXPORT(int top = 20); +EXPORT(int right = 30); +EXPORT(int bottom = 40); + +EXPORT(RECT) ReturnRect(int i, RECT ar, RECT br, POINT cp, RECT dr,
RECT *er, POINT fp, RECT gr)[](#l2.13)
- /*Check input */
- if (ar.left + br->left + dr.left + er->left + gr.left != left * 5)
- {
ar.left = 100;[](#l2.18)
return ar;[](#l2.19)
- }
- if (ar.right + br->right + dr.right + er->right + gr.right != right * 5)
- {
ar.right = 100;[](#l2.23)
return ar;[](#l2.24)
- }
- if (cp.x != fp.x)
- {
ar.left = -100;[](#l2.28)
- }
- if (cp.y != fp.y)
- {
ar.left = -200;[](#l2.32)
- }
- switch(i)
- {
- case 0:
return ar;[](#l2.37)
break;[](#l2.38)
- case 1:
return dr;[](#l2.40)
break;[](#l2.41)
- case 2:
return gr;[](#l2.43)
break;[](#l2.44)
+} + typedef struct { short x; short y;
--- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1140,9 +1140,6 @@ PyObject *_ctypes_callproc(PPROC pProc, for (i = 0; i < argcount; ++i) { atypes[i] = args[i].ffi_type; if (atypes[i]->type == FFI_TYPE_STRUCT -#ifdef _WIN64
&& atypes[i]->size <= sizeof(void *)[](#l3.8)
-#endif ) avalues[i] = (void *)args[i].value.p; else
--- a/Modules/_ctypes/libffi_msvc/ffi.c +++ b/Modules/_ctypes/libffi_msvc/ffi.c @@ -102,6 +102,15 @@ void ffi_prep_args(char *stack, extended FFI_ASSERT(0); } } +#ifdef _WIN64
else if (z > 8)[](#l4.8)
{[](#l4.9)
/* On Win64, if a single argument takes more than 8 bytes,[](#l4.10)
then it is always passed by reference. */[](#l4.11)
*(void **)argp = *p_argv;[](#l4.12)
z = 8;[](#l4.13)
}[](#l4.14)
+#endif else { memcpy(argp, *p_argv, z); @@ -124,7 +133,6 @@ ffi_status ffi_prep_cif_machdep(ffi_cif switch (cif->rtype->type) { case FFI_TYPE_VOID:
- case FFI_TYPE_STRUCT: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: @@ -132,6 +140,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif cif->flags = (unsigned) cif->rtype->type; break;
- case FFI_TYPE_STRUCT:
/* MSVC returns small structures in registers. Put in cif->flags[](#l4.32)
the value FFI_TYPE_STRUCT only if the structure is big enough;[](#l4.33)
otherwise, put the 4- or 8-bytes integer type. */[](#l4.34)
if (cif->rtype->size <= 4)[](#l4.35)
cif->flags = FFI_TYPE_INT;[](#l4.36)
else if (cif->rtype->size <= 8)[](#l4.37)
cif->flags = FFI_TYPE_SINT64;[](#l4.38)
else[](#l4.39)
cif->flags = FFI_TYPE_STRUCT;[](#l4.40)
break;[](#l4.41)
+ case FFI_TYPE_UINT64: #ifdef _WIN64 case FFI_TYPE_POINTER: @@ -201,8 +221,7 @@ ffi_call(/@dependent@/ ffi_cif cif, #else case FFI_SYSV: /@-usedef@*/
/* Function call needs at least 40 bytes stack size, on win64 AMD64 */[](#l4.50)
return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40,[](#l4.51)
return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes,[](#l4.52) cif->flags, ecif.rvalue, fn);[](#l4.53) /*@=usedef@*/[](#l4.54) break;[](#l4.55)
@@ -227,7 +246,7 @@ void * #else static void __fastcall #endif -ffi_closure_SYSV (ffi_closure *closure, int *argp) +ffi_closure_SYSV (ffi_closure *closure, char *argp) { // this is our return value storage long double res; @@ -237,7 +256,7 @@ ffi_closure_SYSV (ffi_closure *closure, void **arg_area; unsigned short rtype; void resp = (void)&res;
- void args = argp + sizeof(void); cif = closure->cif; arg_area = (void**) alloca (cif->nargs * sizeof (void*));
--- a/Modules/_ctypes/libffi_msvc/prep_cif.c +++ b/Modules/_ctypes/libffi_msvc/prep_cif.c @@ -116,9 +116,9 @@ ffi_status ffi_prep_cif(/@out@/ /@par #if !defined M68K && !defined x86_64 && !defined S390 / Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT
/* MSVC returns small structures in registers. But we have a different[](#l5.7)
workaround: pretend int32 or int64 return type, and converting to[](#l5.8)
structure afterwards. */[](#l5.9)
&& (cif->rtype->size > 8) /* MSVC returns small structs in registers */[](#l5.11)
+#endif #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif @@ -145,6 +145,10 @@ ffi_status ffi_prep_cif(/@out@/ /@par && cif->abi != FFI_V9)) bytes += sizeof(void); else +#elif defined (_WIN64)
if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8))[](#l5.21)
bytes += sizeof(void*);[](#l5.22)
else[](#l5.23)
#endif { #if !defined(_MSC_VER) && !defined(MINGW32) @@ -168,6 +172,12 @@ ffi_status ffi_prep_cif(/@out@/ /*@par #endif } +#ifdef _WIN64
- /* Function call needs at least 40 bytes stack size, on win64 AMD64 */
- if (bytes < 40)
bytes = 40;[](#l5.34)
+#endif + cif->bytes = bytes; /* Perform machine dependent cif processing */
--- a/Modules/_ctypes/libffi_msvc/types.c +++ b/Modules/_ctypes/libffi_msvc/types.c @@ -43,7 +43,7 @@ FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_T FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X [](#l6.6)