summaryrefslogtreecommitdiffstats
path: root/Modules/_ctypes
diff options
context:
space:
mode:
authorVladimir Matveev <v2matveev@outlook.com>2018-09-16 05:36:29 (GMT)
committerVictor Stinner <vstinner@redhat.com>2018-09-16 05:36:29 (GMT)
commit7843caeb909bd907e903606414e238db4082315a (patch)
tree92d45753687dc2e26bea648ce2ba045e4e8e6c4a /Modules/_ctypes
parent10a428b64b3f224e2ccd40ff2afb141b9b3425b1 (diff)
downloadcpython-7843caeb909bd907e903606414e238db4082315a.zip
cpython-7843caeb909bd907e903606414e238db4082315a.tar.gz
cpython-7843caeb909bd907e903606414e238db4082315a.tar.bz2
bpo-34603, ctypes/libffi_msvc: Fix returning structs from functions (GH-9258)
Diffstat (limited to 'Modules/_ctypes')
-rw-r--r--Modules/_ctypes/_ctypes_test.c194
-rw-r--r--Modules/_ctypes/callproc.c4
-rw-r--r--Modules/_ctypes/libffi_msvc/ffi.c19
-rw-r--r--Modules/_ctypes/libffi_msvc/ffi.h3
-rw-r--r--Modules/_ctypes/libffi_msvc/prep_cif.c7
5 files changed, 221 insertions, 6 deletions
diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c
index 620a3c6..0152945 100644
--- a/Modules/_ctypes/_ctypes_test.c
+++ b/Modules/_ctypes/_ctypes_test.c
@@ -661,6 +661,200 @@ EXPORT(void) TwoOutArgs(int a, int *pi, int b, int *pj)
}
#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
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); }
#endif
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index bdc3728..ba154fe 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -715,9 +715,9 @@ ffi_type *_ctypes_get_ffi_type(PyObject *obj)
It returns small structures in registers
*/
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;
- else if (dict->ffi_type_pointer.size <= 8)
+ else if (can_return_struct_as_sint64 (dict->ffi_type_pointer.size))
return &ffi_type_sint64;
}
#endif
diff --git a/Modules/_ctypes/libffi_msvc/ffi.c b/Modules/_ctypes/libffi_msvc/ffi.c
index 91a27dc..d202b15 100644
--- a/Modules/_ctypes/libffi_msvc/ffi.c
+++ b/Modules/_ctypes/libffi_msvc/ffi.c
@@ -145,6 +145,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
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 */
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
the value FFI_TYPE_STRUCT only if the structure is big enough;
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;
- else if (cif->rtype->size <= 8)
+ else if (can_return_struct_as_sint64(cif->rtype->size))
cif->flags = FFI_TYPE_SINT64;
else
cif->flags = FFI_TYPE_STRUCT;
diff --git a/Modules/_ctypes/libffi_msvc/ffi.h b/Modules/_ctypes/libffi_msvc/ffi.h
index efb14c5..ba74202 100644
--- a/Modules/_ctypes/libffi_msvc/ffi.h
+++ b/Modules/_ctypes/libffi_msvc/ffi.h
@@ -136,6 +136,9 @@ typedef struct _ffi_type
/*@null@*/ struct _ffi_type **elements;
} ffi_type;
+int can_return_struct_as_int(size_t);
+int can_return_struct_as_sint64(size_t);
+
/* These are defined in types.c */
extern ffi_type ffi_type_void;
extern ffi_type ffi_type_uint8;
diff --git a/Modules/_ctypes/libffi_msvc/prep_cif.c b/Modules/_ctypes/libffi_msvc/prep_cif.c
index b07a2e6..022435e 100644
--- a/Modules/_ctypes/libffi_msvc/prep_cif.c
+++ b/Modules/_ctypes/libffi_msvc/prep_cif.c
@@ -117,7 +117,8 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#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
#ifdef SPARC
&& (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*);
else
#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*);
else
#endif