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

gh-97588: Fix ctypes structs #97702

Open
wants to merge 62 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
7922585
gh-97588: Fix ctypes structs
matthiasgoergens Oct 1, 2022
2307932
📜🤖 Added by blurb_it.
blurb-it Oct 1, 2022
47f826c
Handling pack as well
matthiasgoergens Oct 1, 2022
5a32211
Handle basedict, too
matthiasgoergens Oct 1, 2022
8d79d8f
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 2, 2022
2d07375
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 3, 2022
8bc8535
Merge remote-tracking branch 'matthias/fix-bitfield-clean' into fix-b…
matthiasgoergens Oct 5, 2022
c3d162b
Merge remote-tracking branch 'origin/main' into fix-bitfield-clean
matthiasgoergens Oct 5, 2022
e5ed9ac
Split windows and linux
matthiasgoergens Oct 5, 2022
b0f9819
Compiles
matthiasgoergens Oct 5, 2022
2dee0e3
Abstract out proto stuff
matthiasgoergens Oct 5, 2022
79ef347
Clean align
matthiasgoergens Oct 5, 2022
6170dad
Hypothesis tests pass
matthiasgoergens Oct 5, 2022
871ca1a
Formatting
matthiasgoergens Oct 5, 2022
c162144
Clean up
matthiasgoergens Oct 5, 2022
a57cf2c
Adapt tests for Windows
matthiasgoergens Oct 5, 2022
3f7c4cc
Fix order
matthiasgoergens Oct 5, 2022
e39a271
Fix alignment test
matthiasgoergens Oct 5, 2022
359ed58
Merge remote-tracking branch 'origin/main' into fix-bitfield-clean
matthiasgoergens Oct 5, 2022
52ef8d2
Avoid casting
matthiasgoergens Oct 5, 2022
e8102c4
Fixup
matthiasgoergens Oct 5, 2022
600e144
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 5, 2022
9bad706
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 5, 2022
5121857
Merge remote-tracking branch 'origin/main' into fix-bitfield-clean
matthiasgoergens Oct 6, 2022
6cd27ea
Merge remote-tracking branch 'origin/main' into fix-bitfield-clean
matthiasgoergens Oct 8, 2022
6b6fa8a
Add ability to force msvc compatibility even when not doing any packing
matthiasgoergens Oct 8, 2022
ca9d580
More tests
matthiasgoergens Oct 8, 2022
1401ee4
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 9, 2022
235fa68
Big endian works
matthiasgoergens Oct 9, 2022
a534e18
Merge remote-tracking branch 'matthias/fix-bitfield-clean' into fix-b…
matthiasgoergens Oct 9, 2022
53db061
More tests
matthiasgoergens Oct 9, 2022
9c249c3
More asserts
matthiasgoergens Oct 9, 2022
3cf4747
Drop unneeded parameters
matthiasgoergens Oct 9, 2022
8beddb9
Drop unneeded parameters
matthiasgoergens Oct 9, 2022
9b64ff6
Drop unneeded parameters
matthiasgoergens Oct 9, 2022
4d0dab5
Clean up
matthiasgoergens Oct 9, 2022
bf98667
Explain
matthiasgoergens Oct 9, 2022
8223063
More cleanup
matthiasgoergens Oct 9, 2022
e80a09a
More cleanup
matthiasgoergens Oct 9, 2022
33a10fb
More cleanup
matthiasgoergens Oct 9, 2022
0f3c5a3
Move common assert
matthiasgoergens Oct 9, 2022
47eca3c
Break line
matthiasgoergens Oct 9, 2022
456afd0
Clean TODO
matthiasgoergens Oct 9, 2022
bc799ac
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 9, 2022
212cf13
Fix test for Windows
matthiasgoergens Oct 9, 2022
e7e5ae9
Merge remote-tracking branch 'matthias/fix-bitfield-clean' into fix-b…
matthiasgoergens Oct 9, 2022
45e26ec
Remove warning
matthiasgoergens Oct 9, 2022
ab42187
Port test from PR-19850
matthiasgoergens Oct 9, 2022
640c062
Fix assert
matthiasgoergens Oct 9, 2022
f3e04af
Revert "Port test from PR-19850"
matthiasgoergens Oct 9, 2022
bff34a1
Support gcc's packed structs
matthiasgoergens Oct 9, 2022
5d6f0f7
Remove gcc_packed experiment
matthiasgoergens Oct 9, 2022
d9c1fca
Fix test
matthiasgoergens Oct 10, 2022
cc9ea8a
Fix ms_struct
matthiasgoergens Oct 10, 2022
1554083
Fix ms_struct
matthiasgoergens Oct 10, 2022
a86eadc
Indenting
matthiasgoergens Oct 10, 2022
eefa1ad
Merge remote-tracking branch 'origin/main' into fix-bitfield-clean
matthiasgoergens Oct 10, 2022
28c7fe7
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 10, 2022
f0a92b0
Fix miscounted parens
matthiasgoergens Oct 10, 2022
a3a390b
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 10, 2022
823f1eb
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 11, 2022
77e0328
Merge branch 'main' into fix-bitfield-clean
matthiasgoergens Oct 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -3,6 +3,7 @@
from test import support
import unittest
import os
import sys

import _ctypes_test

@@ -28,6 +29,30 @@ class BITS(Structure):
func = CDLL(_ctypes_test.__file__).unpack_bitfields
func.argtypes = POINTER(BITS), c_char


class BITS_msvc(Structure):
_ms_struct_ = 1
_fields_ = [("A", c_int, 1),
("B", c_int, 2),
("C", c_int, 3),
("D", c_int, 4),
("E", c_int, 5),
("F", c_int, 6),
("G", c_int, 7),
("H", c_int, 8),
("I", c_int, 9),

("M", c_short, 1),
("N", c_short, 2),
("O", c_short, 3),
("P", c_short, 4),
("Q", c_short, 5),
("R", c_short, 6),
("S", c_short, 7)]

func_msvc = CDLL(_ctypes_test.__file__).unpack_bitfields_msvc
func_msvc.argtypes = POINTER(BITS_msvc), c_char

##for n in "ABCDEFGHIMNOPQRS":
## print n, hex(getattr(BITS, n).size), getattr(BITS, n).offset

@@ -40,8 +65,6 @@ def test_ints(self):
setattr(b, name, i)
self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii')))

# bpo-46913: _ctypes/cfield.c h_get() has an undefined behavior
@support.skip_if_sanitizer(ub=True)
def test_shorts(self):
b = BITS()
name = "M"
@@ -51,7 +74,24 @@ def test_shorts(self):
for name in "MNOPQRS":
b = BITS()
setattr(b, name, i)
self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii')))
self.assertEqual(
getattr(b, name),
func(byref(b), (name.encode('ascii'))),
(name, i))

def test_shorts_msvc_mode(self):
b = BITS_msvc()
name = "M"
if func_msvc(byref(b), name.encode('ascii')) == 999:
self.skipTest("Compiler does not support signed short bitfields")
for i in range(256):
for name in "MNOPQRS":
b = BITS_msvc()
setattr(b, name, i)
self.assertEqual(
getattr(b, name),
func_msvc(byref(b), name.encode('ascii')),
(name, i))

signed_int_types = (c_byte, c_short, c_int, c_long, c_longlong)
unsigned_int_types = (c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong)
@@ -236,6 +276,157 @@ class X(Structure):
else:
self.assertEqual(sizeof(X), sizeof(c_int) * 2)

def test_mixed_5(self):
class X(Structure):
_fields_ = [
('A', c_uint, 1),
('B', c_ushort, 16)]
a = X()
a.A = 0
a.B = 1
self.assertEqual(1, a.B)

def test_mixed_6(self):
class X(Structure):
_fields_ = [
('A', c_ulonglong, 1),
('B', c_uint, 32)]
a = X()
a.A = 0
a.B = 1
self.assertEqual(1, a.B)

def test_mixed_7(self):
class X(Structure):
_fields_ = [
("A", c_uint),
('B', c_uint, 20),
('C', c_ulonglong, 24)]
self.assertEqual(16, sizeof(X))

def test_mixed_8(self):
class Foo(Structure):
_fields_ = [
("A", c_uint),
("B", c_uint, 32),
("C", c_ulonglong, 1),
]

class Bar(Structure):
_fields_ = [
("A", c_uint),
("B", c_uint),
("C", c_ulonglong, 1),
]
self.assertEqual(sizeof(Foo), sizeof(Bar))

def test_mixed_9(self):
class X(Structure):
_fields_ = [
("A", c_uint8),
("B", c_uint, 1),
]
if sys.platform == 'win32':
self.assertEqual(8, sizeof(X))
else:
self.assertEqual(4, sizeof(X))

def test_mixed_10(self):
class X(Structure):
_fields_ = [
("A", c_uint32, 1),
("B", c_uint64, 1),
]
if sys.platform == 'win32':
self.assertEqual(8, alignment(X))
self.assertEqual(16, sizeof(X))
else:
self.assertEqual(8, alignment(X))
self.assertEqual(8, sizeof(X))

def test_gh_95496(self):
for field_width in range(1, 33):
class TestStruct(Structure):
_fields_ = [
("Field1", c_uint32, field_width),
("Field2", c_uint8, 8)
]

cmd = TestStruct()
cmd.Field2 = 1
self.assertEqual(1, cmd.Field2)

def test_gh_84039(self):
class Bad(Structure):
_pack_ = 1
_fields_ = [
("a0", c_uint8, 1),
("a1", c_uint8, 1),
("a2", c_uint8, 1),
("a3", c_uint8, 1),
("a4", c_uint8, 1),
("a5", c_uint8, 1),
("a6", c_uint8, 1),
("a7", c_uint8, 1),
("b0", c_uint16, 4),
("b1", c_uint16, 12),
]


class GoodA(Structure):
_pack_ = 1
_fields_ = [
("a0", c_uint8, 1),
("a1", c_uint8, 1),
("a2", c_uint8, 1),
("a3", c_uint8, 1),
("a4", c_uint8, 1),
("a5", c_uint8, 1),
("a6", c_uint8, 1),
("a7", c_uint8, 1),
]


class Good(Structure):
_pack_ = 1
_fields_ = [
("a", GoodA),
("b0", c_uint16, 4),
("b1", c_uint16, 12),
]

self.assertEqual(3, sizeof(Bad))
self.assertEqual(3, sizeof(Good))

def test_gh_73939(self):
class MyStructure(Structure):
_pack_ = 1
_fields_ = [
("P", c_uint16),
("L", c_uint16, 9),
("Pro", c_uint16, 1),
("G", c_uint16, 1),
("IB", c_uint16, 1),
("IR", c_uint16, 1),
("R", c_uint16, 3),
("T", c_uint32, 10),
("C", c_uint32, 20),
("R2", c_uint32, 2)
]
self.assertEqual(8, sizeof(MyStructure))

def test_gh_86098(self):
class X(Structure):
_fields_ = [
("a", c_uint8, 8),
("b", c_uint8, 8),
("c", c_uint32, 16)
]
if sys.platform == 'win32':
self.assertEqual(8, sizeof(X))
else:
self.assertEqual(4, sizeof(X))

def test_anon_bitfields(self):
# anonymous bit-fields gave a strange error message
class X(Structure):
@@ -0,0 +1 @@
Fix ctypes construction of structs from description.
@@ -592,7 +592,7 @@ struct BITS {
*/
#ifndef __xlc__
#define SIGNED_SHORT_BITFIELDS
short M: 1, N: 2, O: 3, P: 4, Q: 5, R: 6, S: 7;
signed short M: 1, N: 2, O: 3, P: 4, Q: 5, R: 6, S: 7;
#endif
};

@@ -622,6 +622,49 @@ EXPORT(int) unpack_bitfields(struct BITS *bits, char name)
return 999;
}

struct
#ifndef MS_WIN32
__attribute__ ((ms_struct))
#endif
BITS_msvc
{
signed int A: 1, B:2, C:3, D:4, E: 5, F: 6, G: 7, H: 8, I: 9;
/*
* The test case needs/uses "signed short" bitfields, but the
* IBM XLC compiler does not support this
*/
#ifndef __xlc__
#define SIGNED_SHORT_BITFIELDS
signed short M: 1, N: 2, O: 3, P: 4, Q: 5, R: 6, S: 7;
#endif
};

EXPORT(int) unpack_bitfields_msvc(struct BITS_msvc *bits, char name)
{
switch (name) {
case 'A': return bits->A;
case 'B': return bits->B;
case 'C': return bits->C;
case 'D': return bits->D;
case 'E': return bits->E;
case 'F': return bits->F;
case 'G': return bits->G;
case 'H': return bits->H;
case 'I': return bits->I;

#ifdef SIGNED_SHORT_BITFIELDS
case 'M': return bits->M;
case 'N': return bits->N;
case 'O': return bits->O;
case 'P': return bits->P;
case 'Q': return bits->Q;
case 'R': return bits->R;
case 'S': return bits->S;
#endif
}
return 999;
}

static PyMethodDef module_methods[] = {
/* {"get_last_tf_arg_s", get_last_tf_arg_s, METH_NOARGS},
{"get_last_tf_arg_u", get_last_tf_arg_u, METH_NOARGS},