From 2b824908874a8853d759d588eb5e846d95a9b9f7 Mon Sep 17 00:00:00 2001 From: Sam Price Date: Sun, 26 Mar 2023 22:44:19 -0400 Subject: [PATCH 1/2] gh-73939: Fix bitfiled not matching C on mac/linux. --- Lib/test/test_ctypes/test_structures.py | 24 ++++++++++++++++++++++++ Modules/_ctypes/_ctypes_test.c | 25 +++++++++++++++++++++++++ Modules/_ctypes/cfield.c | 1 + 3 files changed, 50 insertions(+) diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index df39dc7f50d3f7..9c948fb2b066a2 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -738,6 +738,30 @@ class Test8(Union): self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes ' 'a union by value, which is unsupported.') + def test_bitfield_matches_c(self): + class Test9(Structure): + _pack_ = 1 + _fields_ = (('A', c_uint16), # 2 bytes + ('B', c_uint16, 9), + ('C', c_uint16, 1), + ('D', c_uint16, 1), + ('E', c_uint16, 1), + ('F', c_uint16, 1), + ('G', c_uint16, 3), # 4 bytes + ('H', c_uint32, 10), + ('I', c_uint32, 20), + ('J', c_uint32, 2)) # 8 bytes + dll = CDLL(_ctypes_test.__file__) + func = dll._testfunc_bitfield_by_reference3 + func.restype = c_long + func.argtypes = (POINTER(Test9),c_long,) + ind = 0 + for field in Test9._fields_: + test9 = Test9() + setattr(test9,field[0], 1) + self.assertEqual(func(test9, ind), 1) + ind += 1 + class PointerMemberTestCase(unittest.TestCase): def test(self): diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index a8811d03cc91a2..f4891e5710fb26 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -231,6 +231,31 @@ _testfunc_bitfield_by_reference2(Test7 *in) { return result; } +typedef struct{ + uint16_t A ; + uint16_t B : 9; + uint16_t C : 1; + uint16_t D : 1; + uint16_t E : 1; + uint16_t F : 1; + uint16_t G : 3; + uint32_t H : 10; + uint32_t I : 20; + uint32_t J : 2; +} Test9; + +EXPORT(long) +_testfunc_bitfield_by_reference3(Test9 *in, long pos) { + long data[] = {in->A , in->B , in->C , in->D , in->E , in->F , in->G , in->H , in->I , in->J}; + long data_length = (long) (sizeof(data)/sizeof(data[0])); + if(pos < 0) + return -1; + if(pos >= data_length) + return -1; + + return data[pos]; +} + typedef union { signed int A: 1, B:2, C:3, D:2; } Test8; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 796a1bec966de1..a4ae2a2b284590 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -86,6 +86,7 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index, #ifndef MS_WIN32 } else if (bitsize /* this is a bitfield request */ && *pfield_size /* we have a bitfield open */ + && *pfield_size != *pbitofs /* Current field has been filled, start new one */ && dict->size * 8 >= *pfield_size && (*pbitofs + bitsize) <= dict->size * 8) { /* expand bit field */ From 919010f0fbb23d1882c44ec79e421d719a8f502a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:52:13 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/C API/2023-03-27-03-52-12.gh-issue-73939.aOzhdU.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/C API/2023-03-27-03-52-12.gh-issue-73939.aOzhdU.rst diff --git a/Misc/NEWS.d/next/C API/2023-03-27-03-52-12.gh-issue-73939.aOzhdU.rst b/Misc/NEWS.d/next/C API/2023-03-27-03-52-12.gh-issue-73939.aOzhdU.rst new file mode 100644 index 00000000000000..a77b5325727e4a --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-03-27-03-52-12.gh-issue-73939.aOzhdU.rst @@ -0,0 +1,2 @@ +Fixes bitfield ABI for Linux/Mac for certain bitfields. +Adds unit test to verify C bitfield ABI matches python ABI.