Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
7843caeb
Commit
7843caeb
authored
Sep 15, 2018
by
Vladimir Matveev
Committed by
Victor Stinner
Sep 15, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-34603, ctypes/libffi_msvc: Fix returning structs from functions (GH-9258)
parent
10a428b6
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
240 additions
and
6 deletions
+240
-6
Lib/ctypes/test/test_win32.py
Lib/ctypes/test/test_win32.py
+18
-0
Misc/NEWS.d/next/Windows/2018-09-13-08-29-04.bpo-34603.2AB7sc.rst
...S.d/next/Windows/2018-09-13-08-29-04.bpo-34603.2AB7sc.rst
+1
-0
Modules/_ctypes/_ctypes_test.c
Modules/_ctypes/_ctypes_test.c
+194
-0
Modules/_ctypes/callproc.c
Modules/_ctypes/callproc.c
+2
-2
Modules/_ctypes/libffi_msvc/ffi.c
Modules/_ctypes/libffi_msvc/ffi.c
+17
-2
Modules/_ctypes/libffi_msvc/ffi.h
Modules/_ctypes/libffi_msvc/ffi.h
+3
-0
Modules/_ctypes/libffi_msvc/prep_cif.c
Modules/_ctypes/libffi_msvc/prep_cif.c
+5
-2
No files found.
Lib/ctypes/test/test_win32.py
View file @
7843caeb
...
...
@@ -54,6 +54,24 @@ class FunctionCallTestCase(unittest.TestCase):
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'
)
class
TestWintypes
(
unittest
.
TestCase
):
def
test_HWND
(
self
):
...
...
Misc/NEWS.d/next/Windows/2018-09-13-08-29-04.bpo-34603.2AB7sc.rst
0 → 100644
View file @
7843caeb
Fix returning structs from functions produced by MSVC
Modules/_ctypes/_ctypes_test.c
View file @
7843caeb
...
...
@@ -660,6 +660,200 @@ EXPORT(void) TwoOutArgs(int a, int *pi, int b, int *pj)
*
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
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
);
}
...
...
Modules/_ctypes/callproc.c
View file @
7843caeb
...
...
@@ -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
...
...
Modules/_ctypes/libffi_msvc/ffi.c
View file @
7843caeb
...
...
@@ -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
(
c
if
->
rtype
->
size
<=
4
)
if
(
c
an_return_struct_as_int
(
cif
->
rtype
->
size
)
)
cif
->
flags
=
FFI_TYPE_INT
;
else
if
(
c
if
->
rtype
->
size
<=
8
)
else
if
(
c
an_return_struct_as_sint64
(
cif
->
rtype
->
size
)
)
cif
->
flags
=
FFI_TYPE_SINT64
;
else
cif
->
flags
=
FFI_TYPE_STRUCT
;
...
...
Modules/_ctypes/libffi_msvc/ffi.h
View file @
7843caeb
...
...
@@ -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
;
...
...
Modules/_ctypes/libffi_msvc/prep_cif.c
View file @
7843caeb
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment