Skip to content

Commit 47c8df6

Browse files
[3.13] gh-132673: Fix a crash with zero-alignment in ctypes.Structure (#132695)
1 parent 38f305b commit 47c8df6

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

Lib/test/test_ctypes/test_aligned_structures.py

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from ctypes import (
22
c_char, c_uint32, c_uint16, c_ubyte, c_byte, alignment, sizeof,
33
BigEndianStructure, LittleEndianStructure,
4-
BigEndianUnion, LittleEndianUnion,
4+
BigEndianUnion, LittleEndianUnion, Structure
55
)
66
import struct
77
import unittest
@@ -281,6 +281,41 @@ class Main(sbase):
281281
self.assertEqual(main.b.y, 3)
282282
self.assertEqual(main.c, 4)
283283

284+
def test_negative_align(self):
285+
for base in (Structure, LittleEndianStructure, BigEndianStructure):
286+
with (
287+
self.subTest(base=base),
288+
self.assertRaisesRegex(
289+
ValueError,
290+
'_align_ must be a non-negative integer',
291+
)
292+
):
293+
class MyStructure(base):
294+
_align_ = -1
295+
_fields_ = []
296+
297+
def test_zero_align_no_fields(self):
298+
for base in (Structure, LittleEndianStructure, BigEndianStructure):
299+
with self.subTest(base=base):
300+
class MyStructure(base):
301+
_align_ = 0
302+
_fields_ = []
303+
304+
self.assertEqual(alignment(MyStructure), 1)
305+
self.assertEqual(alignment(MyStructure()), 1)
306+
307+
def test_zero_align_with_fields(self):
308+
for base in (Structure, LittleEndianStructure, BigEndianStructure):
309+
with self.subTest(base=base):
310+
class MyStructure(base):
311+
_align_ = 0
312+
_fields_ = [
313+
("x", c_ubyte),
314+
]
315+
316+
self.assertEqual(alignment(MyStructure), 1)
317+
self.assertEqual(alignment(MyStructure()), 1)
318+
284319

285320
if __name__ == '__main__':
286321
unittest.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash when using ``_align_ = 0`` and ``_fields_ = []`` in a
2+
:class:`ctypes.Structure`.

Modules/_ctypes/stgdict.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
383383
size = 0;
384384
align = 0;
385385
union_size = 0;
386-
total_align = forced_alignment;
386+
total_align = forced_alignment == 0 ? 1 : forced_alignment;
387387
stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
388388
stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
389389
if (stginfo->ffi_type_pointer.elements == NULL) {
@@ -570,6 +570,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
570570
}
571571

572572
/* Adjust the size according to the alignment requirements */
573+
assert(total_align != 0);
573574
aligned_size = ((size + total_align - 1) / total_align) * total_align;
574575

575576
if (isStruct) {

0 commit comments

Comments
 (0)