Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fixed bpo-29565: Corrected ctypes passing of large structs by value on Windows AMD64. #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Lib/ctypes/test/test_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def callback(a, b, c, d, e):
def test_callback_large_struct(self):
class Check: pass

# This should mirror the structure in Modules/_ctypes/_ctypes_test.c
class X(Structure):
_fields_ = [
('first', c_ulong),
Expand All @@ -255,6 +256,11 @@ def callback(check, s):
check.first = s.first
check.second = s.second
check.third = s.third
# See issue #29565.
# The structure should be passed by value, so
# any changes to it should not be reflected in
# the value passed
s.first = s.second = s.third = 0x0badf00d

check = Check()
s = X()
Expand All @@ -275,6 +281,11 @@ def callback(check, s):
self.assertEqual(check.first, 0xdeadbeef)
self.assertEqual(check.second, 0xcafebabe)
self.assertEqual(check.third, 0x0bad1dea)
# See issue #29565.
# Ensure that the original struct is unchanged.
self.assertEqual(s.first, check.first)
self.assertEqual(s.second, check.second)
self.assertEqual(s.third, check.third)

################################################################

Expand Down
23 changes: 23 additions & 0 deletions Lib/ctypes/test/test_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from ctypes.test import need_symbol
from struct import calcsize
import _testcapi
import _ctypes_test

class SubclassesTest(unittest.TestCase):
def test_subclass(self):
Expand Down Expand Up @@ -391,6 +392,28 @@ class Z(Y):
(1, 0, 0, 0, 0, 0))
self.assertRaises(TypeError, lambda: Z(1, 2, 3, 4, 5, 6, 7))

def test_pass_by_value(self):
# This should mirror the structure in Modules/_ctypes/_ctypes_test.c
class X(Structure):
_fields_ = [
('first', c_ulong),
('second', c_ulong),
('third', c_ulong),
]

s = X()
s.first = 0xdeadbeef
s.second = 0xcafebabe
s.third = 0x0bad1dea
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_large_struct_update_value
func.argtypes = (X,)
func.restype = None
func(s)
self.assertEqual(s.first, 0xdeadbeef)
self.assertEqual(s.second, 0xcafebabe)
self.assertEqual(s.third, 0x0bad1dea)

class PointerMemberTestCase(unittest.TestCase):

def test(self):
Expand Down
13 changes: 13 additions & 0 deletions Modules/_ctypes/_ctypes_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ _testfunc_cbk_large_struct(Test in, void (*func)(Test))
func(in);
}

/*
* See issue 29565. Update a structure passed by value;
* the caller should not see any change.
*/

EXPORT(void)
_testfunc_large_struct_update_value(Test in)
{
in.first = 0x0badf00d;
in.second = 0x0badf00d;
in.third = 0x0badf00d;
}

EXPORT(void)testfunc_array(int values[4])
{
printf("testfunc_array %d %d %d %d\n",
Expand Down
10 changes: 10 additions & 0 deletions Modules/_ctypes/libffi_msvc/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,16 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
break;
#else
case FFI_SYSV:
/* If a single argument takes more than 8 bytes,
then a copy is passed by reference. */
for (unsigned i = 0; i < cif->nargs; i++) {
size_t z = cif->arg_types[i]->size;
if (z > 8) {
void *temp = alloca(z);
memcpy(temp, avalue[i], z);
avalue[i] = temp;
}
}
/*@-usedef@*/
return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
Expand Down