mirror of https://github.com/python/cpython
bpo-34603, ctypes/libffi_msvc: Fix returning structs from functions (GH-9258)
This commit is contained in:
parent
10a428b64b
commit
7843caeb90
|
@ -54,6 +54,24 @@ class FunctionCallTestCase(unittest.TestCase):
|
||||||
windll.user32.GetDesktopWindow()
|
windll.user32.GetDesktopWindow()
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
|
||||||
|
class ReturnStructSizesTestCase(unittest.TestCase):
|
||||||
|
def test_sizes(self):
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
for i in range(1, 11):
|
||||||
|
fields = [ (f"f{f}", c_char) for f in range(1, i + 1)]
|
||||||
|
class S(Structure):
|
||||||
|
_fields_ = fields
|
||||||
|
f = getattr(dll, f"TestSize{i}")
|
||||||
|
f.restype = S
|
||||||
|
res = f()
|
||||||
|
for i, f in enumerate(fields):
|
||||||
|
value = getattr(res, f[0])
|
||||||
|
expected = bytes([ord('a') + i])
|
||||||
|
self.assertEquals(value, expected)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
|
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
|
||||||
class TestWintypes(unittest.TestCase):
|
class TestWintypes(unittest.TestCase):
|
||||||
def test_HWND(self):
|
def test_HWND(self):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix returning structs from functions produced by MSVC
|
|
@ -660,6 +660,200 @@ EXPORT(void) TwoOutArgs(int a, int *pi, int b, int *pj)
|
||||||
*pj += b;
|
*pj += b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MS_WIN32
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
} Size1;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
} Size2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
} Size3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
char f4;
|
||||||
|
} Size4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
char f4;
|
||||||
|
char f5;
|
||||||
|
} Size5;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
char f4;
|
||||||
|
char f5;
|
||||||
|
char f6;
|
||||||
|
} Size6;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
char f4;
|
||||||
|
char f5;
|
||||||
|
char f6;
|
||||||
|
char f7;
|
||||||
|
} Size7;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
char f4;
|
||||||
|
char f5;
|
||||||
|
char f6;
|
||||||
|
char f7;
|
||||||
|
char f8;
|
||||||
|
} Size8;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
char f4;
|
||||||
|
char f5;
|
||||||
|
char f6;
|
||||||
|
char f7;
|
||||||
|
char f8;
|
||||||
|
char f9;
|
||||||
|
} Size9;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char f1;
|
||||||
|
char f2;
|
||||||
|
char f3;
|
||||||
|
char f4;
|
||||||
|
char f5;
|
||||||
|
char f6;
|
||||||
|
char f7;
|
||||||
|
char f8;
|
||||||
|
char f9;
|
||||||
|
char f10;
|
||||||
|
} Size10;
|
||||||
|
|
||||||
|
EXPORT(Size1) TestSize1() {
|
||||||
|
Size1 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size2) TestSize2() {
|
||||||
|
Size2 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size3) TestSize3() {
|
||||||
|
Size3 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size4) TestSize4() {
|
||||||
|
Size4 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
f.f4 = 'd';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size5) TestSize5() {
|
||||||
|
Size5 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
f.f4 = 'd';
|
||||||
|
f.f5 = 'e';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size6) TestSize6() {
|
||||||
|
Size6 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
f.f4 = 'd';
|
||||||
|
f.f5 = 'e';
|
||||||
|
f.f6 = 'f';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size7) TestSize7() {
|
||||||
|
Size7 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
f.f4 = 'd';
|
||||||
|
f.f5 = 'e';
|
||||||
|
f.f6 = 'f';
|
||||||
|
f.f7 = 'g';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size8) TestSize8() {
|
||||||
|
Size8 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
f.f4 = 'd';
|
||||||
|
f.f5 = 'e';
|
||||||
|
f.f6 = 'f';
|
||||||
|
f.f7 = 'g';
|
||||||
|
f.f8 = 'h';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size9) TestSize9() {
|
||||||
|
Size9 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
f.f4 = 'd';
|
||||||
|
f.f5 = 'e';
|
||||||
|
f.f6 = 'f';
|
||||||
|
f.f7 = 'g';
|
||||||
|
f.f8 = 'h';
|
||||||
|
f.f9 = 'i';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT(Size10) TestSize10() {
|
||||||
|
Size10 f;
|
||||||
|
f.f1 = 'a';
|
||||||
|
f.f2 = 'b';
|
||||||
|
f.f3 = 'c';
|
||||||
|
f.f4 = 'd';
|
||||||
|
f.f5 = 'e';
|
||||||
|
f.f6 = 'f';
|
||||||
|
f.f7 = 'g';
|
||||||
|
f.f8 = 'h';
|
||||||
|
f.f9 = 'i';
|
||||||
|
f.f10 = 'j';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MS_WIN32
|
#ifdef MS_WIN32
|
||||||
EXPORT(S2H) __stdcall s_ret_2h_func(S2H inp) { return ret_2h_func(inp); }
|
EXPORT(S2H) __stdcall s_ret_2h_func(S2H inp) { return ret_2h_func(inp); }
|
||||||
EXPORT(S8I) __stdcall s_ret_8i_func(S8I inp) { return ret_8i_func(inp); }
|
EXPORT(S8I) __stdcall s_ret_8i_func(S8I inp) { return ret_8i_func(inp); }
|
||||||
|
|
|
@ -715,9 +715,9 @@ ffi_type *_ctypes_get_ffi_type(PyObject *obj)
|
||||||
It returns small structures in registers
|
It returns small structures in registers
|
||||||
*/
|
*/
|
||||||
if (dict->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
|
if (dict->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
|
||||||
if (dict->ffi_type_pointer.size <= 4)
|
if (can_return_struct_as_int(dict->ffi_type_pointer.size))
|
||||||
return &ffi_type_sint32;
|
return &ffi_type_sint32;
|
||||||
else if (dict->ffi_type_pointer.size <= 8)
|
else if (can_return_struct_as_sint64 (dict->ffi_type_pointer.size))
|
||||||
return &ffi_type_sint64;
|
return &ffi_type_sint64;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -145,6 +145,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Per: https://msdn.microsoft.com/en-us/library/7572ztz4.aspx
|
||||||
|
To be returned by value in RAX, user-defined types must have a length
|
||||||
|
of 1, 2, 4, 8, 16, 32, or 64 bits
|
||||||
|
*/
|
||||||
|
int can_return_struct_as_int(size_t s)
|
||||||
|
{
|
||||||
|
return s == 1 || s == 2 || s == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int can_return_struct_as_sint64(size_t s)
|
||||||
|
{
|
||||||
|
return s == 8;
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
/* Perform machine dependent cif processing */
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
{
|
{
|
||||||
|
@ -163,9 +178,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
/* MSVC returns small structures in registers. Put in cif->flags
|
/* MSVC returns small structures in registers. Put in cif->flags
|
||||||
the value FFI_TYPE_STRUCT only if the structure is big enough;
|
the value FFI_TYPE_STRUCT only if the structure is big enough;
|
||||||
otherwise, put the 4- or 8-bytes integer type. */
|
otherwise, put the 4- or 8-bytes integer type. */
|
||||||
if (cif->rtype->size <= 4)
|
if (can_return_struct_as_int(cif->rtype->size))
|
||||||
cif->flags = FFI_TYPE_INT;
|
cif->flags = FFI_TYPE_INT;
|
||||||
else if (cif->rtype->size <= 8)
|
else if (can_return_struct_as_sint64(cif->rtype->size))
|
||||||
cif->flags = FFI_TYPE_SINT64;
|
cif->flags = FFI_TYPE_SINT64;
|
||||||
else
|
else
|
||||||
cif->flags = FFI_TYPE_STRUCT;
|
cif->flags = FFI_TYPE_STRUCT;
|
||||||
|
|
|
@ -136,6 +136,9 @@ typedef struct _ffi_type
|
||||||
/*@null@*/ struct _ffi_type **elements;
|
/*@null@*/ struct _ffi_type **elements;
|
||||||
} ffi_type;
|
} ffi_type;
|
||||||
|
|
||||||
|
int can_return_struct_as_int(size_t);
|
||||||
|
int can_return_struct_as_sint64(size_t);
|
||||||
|
|
||||||
/* These are defined in types.c */
|
/* These are defined in types.c */
|
||||||
extern ffi_type ffi_type_void;
|
extern ffi_type ffi_type_void;
|
||||||
extern ffi_type ffi_type_uint8;
|
extern ffi_type ffi_type_uint8;
|
||||||
|
|
|
@ -117,7 +117,8 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
|
||||||
/* Make space for the return structure pointer */
|
/* Make space for the return structure pointer */
|
||||||
if (cif->rtype->type == FFI_TYPE_STRUCT
|
if (cif->rtype->type == FFI_TYPE_STRUCT
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
&& (cif->rtype->size > 8) /* MSVC returns small structs in registers */
|
&& !can_return_struct_as_int(cif->rtype->size) /* MSVC returns small structs in registers */
|
||||||
|
&& !can_return_struct_as_sint64(cif->rtype->size)
|
||||||
#endif
|
#endif
|
||||||
#ifdef SPARC
|
#ifdef SPARC
|
||||||
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
|
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
|
||||||
|
@ -146,7 +147,9 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
|
||||||
bytes += sizeof(void*);
|
bytes += sizeof(void*);
|
||||||
else
|
else
|
||||||
#elif defined (_WIN64)
|
#elif defined (_WIN64)
|
||||||
if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8))
|
if ((*ptr)->type == FFI_TYPE_STRUCT &&
|
||||||
|
!can_return_struct_as_int((*ptr)->size) &&
|
||||||
|
!can_return_struct_as_sint64((*ptr)->size))
|
||||||
bytes += sizeof(void*);
|
bytes += sizeof(void*);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue