From c46aa6cdbdf4d2b2ae9f53ee1f921ea2c04a252e Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 18 Apr 2025 12:43:40 -0400 Subject: [PATCH 1/4] Fix zero-alignment with ctypes --- .../test_ctypes/test_aligned_structures.py | 37 ++++++++++++++++++- Modules/_ctypes/stgdict.c | 3 +- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_aligned_structures.py b/Lib/test/test_ctypes/test_aligned_structures.py index a208fb9a00966a..8e8ac429900374 100644 --- a/Lib/test/test_ctypes/test_aligned_structures.py +++ b/Lib/test/test_ctypes/test_aligned_structures.py @@ -1,7 +1,7 @@ from ctypes import ( c_char, c_uint32, c_uint16, c_ubyte, c_byte, alignment, sizeof, BigEndianStructure, LittleEndianStructure, - BigEndianUnion, LittleEndianUnion, + BigEndianUnion, LittleEndianUnion, Structure ) import struct import unittest @@ -281,6 +281,41 @@ class Main(sbase): self.assertEqual(main.b.y, 3) self.assertEqual(main.c, 4) + def test_negative_align(self): + for base in (Structure, LittleEndianStructure, BigEndianStructure): + with ( + self.subTest(base=base), + self.assertRaisesRegex( + ValueError, + '_align_ must be a non-negative integer', + ) + ): + class MyStructure(base): + _align_ = -1 + _fields_ = [] + + def test_zero_align_no_fields(self): + for base in (Structure, LittleEndianStructure, BigEndianStructure): + with self.subTest(base=base): + class MyStructure(base): + _align_ = 0 + _fields_ = [] + + self.assertEqual(alignment(MyStructure), 1) + self.assertEqual(alignment(MyStructure()), 1) + + def test_zero_align_with_fields(self): + for base in (Structure, LittleEndianStructure, BigEndianStructure): + with self.subTest(base=base): + class MyStructure(base): + _align_ = 0 + _fields_ = [ + ("x", c_ubyte), + ] + + self.assertEqual(alignment(MyStructure), 1) + self.assertEqual(alignment(MyStructure()), 1) + if __name__ == '__main__': unittest.main() diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index ad82e4891c519a..c7e8bfc3cdff51 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -383,7 +383,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct size = 0; align = 0; union_size = 0; - total_align = forced_alignment; + total_align = forced_alignment != 0 ? forced_alignment : 1; stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT; stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1); if (stginfo->ffi_type_pointer.elements == NULL) { @@ -570,6 +570,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct } /* Adjust the size according to the alignment requirements */ + assert(total_align != 0); aligned_size = ((size + total_align - 1) / total_align) * total_align; if (isStruct) { From e80b023fb2e0729b7cefacd29f8b45d38d2c3e6a Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 18 Apr 2025 12:45:24 -0400 Subject: [PATCH 2/4] Add blurb. --- .../next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst diff --git a/Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst b/Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst new file mode 100644 index 00000000000000..7efd43b0f03e86 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst @@ -0,0 +1,2 @@ +Fix crash when using ``_align_ = 0`` and ``_fields_ = []`` in a +:class:`ctypes.Structure`. From 18d8d932b97738d7d4c7d929d12270237e72e62c Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sat, 19 Apr 2025 09:05:46 -0400 Subject: [PATCH 3/4] Update 2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst b/Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst index 7efd43b0f03e86..db74ef6a324859 100644 --- a/Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst +++ b/Misc/NEWS.d/next/Library/2025-04-18-12-45-18.gh-issue-132673.P7Z3F1.rst @@ -1,2 +1,2 @@ -Fix crash when using ``_align_ = 0`` and ``_fields_ = []`` in a +Fix a crash when using ``_align_ = 0`` and ``_fields_ = []`` in a :class:`ctypes.Structure`. From e5e7b26e5f3c7b44981d0dc8642aa0f066c5b1cf Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sat, 19 Apr 2025 09:05:54 -0400 Subject: [PATCH 4/4] Update stgdict.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Modules/_ctypes/stgdict.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index c7e8bfc3cdff51..5f5e79e5a645fa 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -383,7 +383,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct size = 0; align = 0; union_size = 0; - total_align = forced_alignment != 0 ? forced_alignment : 1; + total_align = forced_alignment == 0 ? 1 : forced_alignment; stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT; stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1); if (stginfo->ffi_type_pointer.elements == NULL) {