Skip to content
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

[3.11] gh-110190: Fix ctypes structs with array on PPCLE64 (GH-112959) #113167

Merged
merged 2 commits into from
Jan 5, 2024
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
232 changes: 84 additions & 148 deletions Lib/ctypes/test/test_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from ctypes.util import find_library
from struct import calcsize
import _ctypes_test
from collections import namedtuple
from test import support

# The following definition is meant to be used from time to time to assist
Expand Down Expand Up @@ -545,36 +546,53 @@ class Vector(Mid):
def test_array_in_struct(self):
# See bpo-22273

# Load the shared library
dll = CDLL(_ctypes_test.__file__)

# These should mirror the structures in Modules/_ctypes/_ctypes_test.c
class Test2(Structure):
_fields_ = [
('data', c_ubyte * 16),
]

class Test3(Structure):
class Test3AParent(Structure):
_fields_ = [
('data', c_float * 2),
]

class Test3A(Test3AParent):
_fields_ = [
('more_data', c_float * 2),
]

class Test3B(Structure):
_fields_ = [
('data', c_double * 2),
]

class Test3A(Structure):
class Test3C(Structure):
_fields_ = [
('data', c_float * 2),
("data", c_double * 4)
]

class Test3B(Test3A):
class Test3D(Structure):
_fields_ = [
('more_data', c_float * 2),
("data", c_double * 8)
]

class Test3E(Structure):
_fields_ = [
("data", c_double * 9)
]

# Load the shared library
dll = CDLL(_ctypes_test.__file__)

# Tests for struct Test2
s = Test2()
expected = 0
for i in range(16):
s.data[i] = i
expected += i
func = dll._testfunc_array_in_struct1
func = dll._testfunc_array_in_struct2
func.restype = c_int
func.argtypes = (Test2,)
result = func(s)
Expand All @@ -583,29 +601,16 @@ class Test3B(Test3A):
for i in range(16):
self.assertEqual(s.data[i], i)

s = Test3()
s.data[0] = 3.14159
s.data[1] = 2.71828
expected = 3.14159 + 2.71828
func = dll._testfunc_array_in_struct2
func.restype = c_double
func.argtypes = (Test3,)
result = func(s)
self.assertEqual(result, expected)
# check the passed-in struct hasn't changed
self.assertEqual(s.data[0], 3.14159)
self.assertEqual(s.data[1], 2.71828)

s = Test3B()
# Tests for struct Test3A
s = Test3A()
s.data[0] = 3.14159
s.data[1] = 2.71828
s.more_data[0] = -3.0
s.more_data[1] = -2.0

expected = 3.14159 + 2.71828 - 5.0
func = dll._testfunc_array_in_struct2a
expected = 3.14159 + 2.71828 - 3.0 - 2.0
func = dll._testfunc_array_in_struct3A
func.restype = c_double
func.argtypes = (Test3B,)
func.argtypes = (Test3A,)
result = func(s)
self.assertAlmostEqual(result, expected, places=6)
# check the passed-in struct hasn't changed
Expand All @@ -614,129 +619,60 @@ class Test3B(Test3A):
self.assertAlmostEqual(s.more_data[0], -3.0, places=6)
self.assertAlmostEqual(s.more_data[1], -2.0, places=6)

@unittest.skipIf(
'ppc64le' in platform.uname().machine,
"gh-110190: currently fails on ppc64le",
)
def test_array_in_struct_registers(self):
dll = CDLL(_ctypes_test.__file__)

class Test3C1(Structure):
_fields_ = [
("data", c_double * 4)
]

class DataType4(Array):
_type_ = c_double
_length_ = 4

class Test3C2(Structure):
_fields_ = [
("data", DataType4)
]

class Test3C3(Structure):
_fields_ = [
("x", c_double),
("y", c_double),
("z", c_double),
("t", c_double)
]

class Test3D1(Structure):
_fields_ = [
("data", c_double * 5)
]

class DataType5(Array):
_type_ = c_double
_length_ = 5

class Test3D2(Structure):
_fields_ = [
("data", DataType5)
]

class Test3D3(Structure):
_fields_ = [
("x", c_double),
("y", c_double),
("z", c_double),
("t", c_double),
("u", c_double)
]

# Tests for struct Test3C
expected = (1.0, 2.0, 3.0, 4.0)
func = dll._testfunc_array_in_struct_set_defaults_3C
func.restype = Test3C1
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3]),
expected
# Test3B, Test3C, Test3D, Test3E have the same logic with different
# sizes hence putting them in a loop.
StructCtype = namedtuple(
"StructCtype",
["cls", "cfunc1", "cfunc2", "items"]
)

func = dll._testfunc_array_in_struct_set_defaults_3C
func.restype = Test3C2
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3]),
expected
)

func = dll._testfunc_array_in_struct_set_defaults_3C
func.restype = Test3C3
result = func()
# check the default values have been set properly
self.assertEqual((result.x, result.y, result.z, result.t), expected)

# Tests for struct Test3D
expected = (1.0, 2.0, 3.0, 4.0, 5.0)
func = dll._testfunc_array_in_struct_set_defaults_3D
func.restype = Test3D1
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3],
result.data[4]),
expected
)

func = dll._testfunc_array_in_struct_set_defaults_3D
func.restype = Test3D2
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3],
result.data[4]),
expected
)

func = dll._testfunc_array_in_struct_set_defaults_3D
func.restype = Test3D3
result = func()
# check the default values have been set properly
self.assertEqual(
(result.x,
result.y,
result.z,
result.t,
result.u),
expected)
structs_to_test = [
StructCtype(
Test3B,
dll._testfunc_array_in_struct3B,
dll._testfunc_array_in_struct3B_set_defaults,
2),
StructCtype(
Test3C,
dll._testfunc_array_in_struct3C,
dll._testfunc_array_in_struct3C_set_defaults,
4),
StructCtype(
Test3D,
dll._testfunc_array_in_struct3D,
dll._testfunc_array_in_struct3D_set_defaults,
8),
StructCtype(
Test3E,
dll._testfunc_array_in_struct3E,
dll._testfunc_array_in_struct3E_set_defaults,
9),
]

for sut in structs_to_test:
s = sut.cls()

# Test for cfunc1
expected = 0
for i in range(sut.items):
float_i = float(i)
s.data[i] = float_i
expected += float_i
func = sut.cfunc1
func.restype = c_double
func.argtypes = (sut.cls,)
result = func(s)
self.assertEqual(result, expected)
# check the passed-in struct hasn't changed
for i in range(sut.items):
self.assertEqual(s.data[i], float(i))

# Test for cfunc2
func = sut.cfunc2
func.restype = sut.cls
result = func()
# check if the default values have been set correctly
for i in range(sut.items):
self.assertEqual(result.data[i], float(i+1))

def test_38368(self):
class U(Union):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix ctypes structs with array on PPC64LE platform by setting ``MAX_STRUCT_SIZE`` to 64 in stgdict. Patch by Diego Russo.
Loading
Loading