Skip to content

Commit 32119e1

Browse files
paulmonzooba
authored andcommitted
bpo-35947: Update Windows to the current version of libffi (GH-11797)
We now use a pre-built libffi binary from our binaries repository, and no longer vendor the full implementation.
1 parent 3396d1e commit 32119e1

24 files changed

+250
-2365
lines changed

Lib/ctypes/test/test_win32.py

-29
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,6 @@
66

77
import _ctypes_test
88

9-
# Only windows 32-bit has different calling conventions.
10-
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
11-
@unittest.skipUnless(sizeof(c_void_p) == sizeof(c_int),
12-
"sizeof c_void_p and c_int differ")
13-
class WindowsTestCase(unittest.TestCase):
14-
def test_callconv_1(self):
15-
# Testing stdcall function
16-
17-
IsWindow = windll.user32.IsWindow
18-
# ValueError: Procedure probably called with not enough arguments
19-
# (4 bytes missing)
20-
self.assertRaises(ValueError, IsWindow)
21-
22-
# This one should succeed...
23-
self.assertEqual(0, IsWindow(0))
24-
25-
# ValueError: Procedure probably called with too many arguments
26-
# (8 bytes in excess)
27-
self.assertRaises(ValueError, IsWindow, 0, 0, 0)
28-
29-
def test_callconv_2(self):
30-
# Calling stdcall function as cdecl
31-
32-
IsWindow = cdll.user32.IsWindow
33-
34-
# ValueError: Procedure called with not enough arguments
35-
# (4 bytes missing) or wrong calling convention
36-
self.assertRaises(ValueError, IsWindow, None)
37-
389
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
3910
class FunctionCallTestCase(unittest.TestCase):
4011
@unittest.skipUnless('MSC' in sys.version, "SEH only supported by MSC")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added current version of libffi to cpython-source-deps.
2+
Change _ctypes to use current version of libffi on Windows.

Modules/_ctypes/_ctypes.c

+21-10
Original file line numberDiff line numberDiff line change
@@ -403,24 +403,35 @@ static PyCArgObject *
403403
StructUnionType_paramfunc(CDataObject *self)
404404
{
405405
PyCArgObject *parg;
406+
CDataObject *copied_self;
406407
StgDictObject *stgdict;
407408

409+
if (self->b_size > sizeof(void*)) {
410+
void *new_ptr = PyMem_Malloc(self->b_size);
411+
if (new_ptr == NULL)
412+
return NULL;
413+
memcpy(new_ptr, self->b_ptr, self->b_size);
414+
copied_self = (CDataObject *)PyCData_AtAddress(
415+
(PyObject *)Py_TYPE(self), new_ptr);
416+
copied_self->b_needsfree = 1;
417+
} else {
418+
copied_self = self;
419+
Py_INCREF(copied_self);
420+
}
421+
408422
parg = PyCArgObject_new();
409-
if (parg == NULL)
423+
if (parg == NULL) {
424+
Py_DECREF(copied_self);
410425
return NULL;
426+
}
411427

412428
parg->tag = 'V';
413-
stgdict = PyObject_stgdict((PyObject *)self);
429+
stgdict = PyObject_stgdict((PyObject *)copied_self);
414430
assert(stgdict); /* Cannot be NULL for structure/union instances */
415431
parg->pffi_type = &stgdict->ffi_type_pointer;
416-
/* For structure parameters (by value), parg->value doesn't contain the structure
417-
data itself, instead parg->value.p *points* to the structure's data
418-
See also _ctypes.c, function _call_function_pointer().
419-
*/
420-
parg->value.p = self->b_ptr;
421-
parg->size = self->b_size;
422-
Py_INCREF(self);
423-
parg->obj = (PyObject *)self;
432+
parg->value.p = copied_self->b_ptr;
433+
parg->size = copied_self->b_size;
434+
parg->obj = (PyObject *)copied_self;
424435
return parg;
425436
}
426437

Modules/_ctypes/callproc.c

+18-34
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,23 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
729729
}
730730
}
731731

732+
#if defined(MS_WIN32) && !defined(_WIN32_WCE)
733+
/*
734+
Per: https://msdn.microsoft.com/en-us/library/7572ztz4.aspx
735+
To be returned by value in RAX, user-defined types must have a length
736+
of 1, 2, 4, 8, 16, 32, or 64 bits
737+
*/
738+
int can_return_struct_as_int(size_t s)
739+
{
740+
return s == 1 || s == 2 || s == 4;
741+
}
742+
743+
int can_return_struct_as_sint64(size_t s)
744+
{
745+
return s == 8;
746+
}
747+
#endif
748+
732749

733750
ffi_type *_ctypes_get_ffi_type(PyObject *obj)
734751
{
@@ -778,12 +795,9 @@ static int _call_function_pointer(int flags,
778795
int *space;
779796
ffi_cif cif;
780797
int cc;
781-
#ifdef MS_WIN32
782-
int delta;
783-
#ifndef DONT_USE_SEH
798+
#if defined(MS_WIN32) && !defined(DONT_USE_SEH)
784799
DWORD dwExceptionCode = 0;
785800
EXCEPTION_RECORD record;
786-
#endif
787801
#endif
788802
/* XXX check before here */
789803
if (restype == NULL) {
@@ -828,7 +842,6 @@ static int _call_function_pointer(int flags,
828842
#ifndef DONT_USE_SEH
829843
__try {
830844
#endif
831-
delta =
832845
#endif
833846
ffi_call(&cif, (void *)pProc, resmem, avalues);
834847
#ifdef MS_WIN32
@@ -860,35 +873,6 @@ static int _call_function_pointer(int flags,
860873
return -1;
861874
}
862875
#endif
863-
#ifdef MS_WIN64
864-
if (delta != 0) {
865-
PyErr_Format(PyExc_RuntimeError,
866-
"ffi_call failed with code %d",
867-
delta);
868-
return -1;
869-
}
870-
#else
871-
if (delta < 0) {
872-
if (flags & FUNCFLAG_CDECL)
873-
PyErr_Format(PyExc_ValueError,
874-
"Procedure called with not enough "
875-
"arguments (%d bytes missing) "
876-
"or wrong calling convention",
877-
-delta);
878-
else
879-
PyErr_Format(PyExc_ValueError,
880-
"Procedure probably called with not enough "
881-
"arguments (%d bytes missing)",
882-
-delta);
883-
return -1;
884-
} else if (delta > 0) {
885-
PyErr_Format(PyExc_ValueError,
886-
"Procedure probably called with too many "
887-
"arguments (%d bytes in excess)",
888-
delta);
889-
return -1;
890-
}
891-
#endif
892876
#endif
893877
if ((flags & FUNCFLAG_PYTHONAPI) && PyErr_Occurred())
894878
return -1;

Modules/_ctypes/libffi_msvc/LICENSE

-20
This file was deleted.

0 commit comments

Comments
 (0)