8000 bpo-30353: Fix pass by value for structs on 64-bit Cygwin/MinGW (GH-1… · python/cpython@9ba3aa4 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9ba3aa4

Browse files
embrayvsajip
authored andcommitted
bpo-30353: Fix pass by value for structs on 64-bit Cygwin/MinGW (GH-1559)
1 parent 897bba7 commit 9ba3aa4

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

Lib/ctypes/test/test_as_parameter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ class S2H(Structure):
169169
s2h = dll.ret_2h_func(self.wrap(inp))
170170
self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
171171

172+
# Test also that the original struct was unmodified (i.e. was passed by
173+
# value)
174+
self.assertEqual((inp.x, inp.y), (99, 88))
175+
172176
def test_struct_return_8H(self):
173177
class S8I(Structure):
174178
_fields_ = [("a", c_int),

Lib/ctypes/test/test_structures.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,28 @@ class X(Structure):
417417
self.assertEqual(s.second, 0xcafebabe)
418418
self.assertEqual(s.third, 0x0bad1dea)
419419

420+
def test_pass_by_value_in_register(self):
421+
class X(Structure):
422+
_fields_ = [
423+
('first', c_uint),
424+
('second', c_uint)
425+
]
426+
427+
s = X()
428+
s.first = 0xdeadbeef
429+
s.second = 0xcafebabe
430+
dll = CDLL(_ctypes_test.__file__)
431+
func = dll._testfunc_reg_struct_update_value
432+
func.argtypes = (X,)
433+
func.restype = None
434+
func(s)
435+
self.assertEqual(s.first, 0xdeadbeef)
436+
self.assertEqual(s.second, 0xcafebabe)
437+
got = X.in_dll(dll, "last_tfrsuv_arg")
438+
self.assertEqual(s.first, got.first)
439+
self.assertEqual(s.second, got.second)
440+
441+
420442
class PointerMemberTestCase(unittest.TestCase):
421443

422444
def test(self):

Modules/_ctypes/_ctypes_test.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,24 @@ _testfunc_large_struct_update_value(Test in)
5757
((volatile Test *)&in)->third = 0x0badf00d;
5858
}
5959

60+
typedef struct {
61+
unsigned int first;
62+
unsigned int second;
63+
} TestReg;
64+
65+
66+
EXPORT(TestReg) last_tfrsuv_arg;
67+
68+
69+
EXPORT(void)
70+
_testfunc_reg_struct_update_value(TestReg in)
71+
{
72+
last_tfrsuv_arg = in;
73+
((volatile TestReg *)&in)->first = 0x0badf00d;
74+
((volatile TestReg *)&in)->second = 0x0badf00d;
75+
}
76+
77+
6078
EXPORT(void)testfunc_array(int values[4])
6179
{
6280
printf("testfunc_array %d %d %d %d\n",

Modules/_ctypes/callproc.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,13 @@ GetComError(HRESULT errcode, GUID *riid, IUnknown *pIunk)
10391039
}
10401040
#endif
10411041

1042+
#if (defined(__x86_64__) && (defined(__MINGW64__) || defined(__CYGWIN__))) || \
1043+
defined(__aarch64__)
1044+
#define CTYPES_PASS_BY_REF_HACK
1045+
#define POW2(x) (((x & ~(x - 1)) == x) ? x : 0)
1046+
#define IS_PASS_BY_REF(x) (x > 8 || !POW2(x))
1047+
#endif
104 8000 8+
10421049
/*
10431050
* Requirements, must be ensured by the caller:
10441051
* - argtuple is tuple of arguments
@@ -1136,8 +1143,20 @@ PyObject *_ctypes_callproc(PPROC pProc,
11361143
}
11371144
for (i = 0; i < argcount; ++i) {
11381145
atypes[i] = args[i].ffi_type;
1139-
if (atypes[i]->type == FFI_TYPE_STRUCT
1140-
)
1146+
#ifdef CTYPES_PASS_BY_REF_HACK
1147+
size_t size = atypes[i]->size;
1148+
if (IS_PASS_BY_REF(size)) {
1149+
void *tmp = alloca(size);
1150+
if (atypes[i]->type == FFI_TYPE_STRUCT)
1151+
memcpy(tmp, args[i].value.p, size);
1152+
else
1153+
memcpy(tmp, (void*)&args[i].value, size);
1154+
1155+
avalues[i] = tmp;
1156+
}
1157+
else
1158+
#endif
1159+
if (atypes[i]->type == FFI_TYPE_STRUCT)
11411160
avalues[i] = (void *)args[i].value.p;
11421161
else
11431162
avalues[i] = (void *)&args[i].value;

0 commit comments

Comments
 (0)
0