Skip to content

Commit 50b0953

Browse files
matthiasgoergensgpsheadencukou
authored andcommitted
pythongh-97588: Align ctypes struct layout to GCC/MSVC (pythonGH-97702)
Structure layout, and especially bitfields, sometimes resulted in clearly wrong behaviour like overlapping fields. This fixes Co-authored-by: Gregory P. Smith <gps@python.org> Co-authored-by: Petr Viktorin <encukou@gmail.com>
1 parent 6f84da0 commit 50b0953

17 files changed

+3286
-188
lines changed

Doc/library/ctypes.rst

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -661,14 +661,18 @@ for debugging because they can provide useful information::
661661
guaranteed by the library to work in the general case. Unions and
662662
structures with bit-fields should always be passed to functions by pointer.
663663

664-
Structure/union alignment and byte order
665-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
666-
667-
By default, Structure and Union fields are aligned in the same way the C
668-
compiler does it. It is possible to override this behavior by specifying a
669-
:attr:`~Structure._pack_` class attribute in the subclass definition.
670-
This must be set to a positive integer and specifies the maximum alignment for the fields.
671-
This is what ``#pragma pack(n)`` also does in MSVC.
664+
Structure/union layout, alignment and byte order
665+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
666+
667+
By default, Structure and Union fields are laid out in the same way the C
668+
compiler does it. It is possible to override this behavior entirely by specifying a
669+
:attr:`~Structure._layout_` class attribute in the subclass definition; see
670+
the attribute documentation for details.
671+
672+
It is possible to specify the maximum alignment for the fields by setting
673+
the :attr:`~Structure._pack_` class attribute to a positive integer.
674+
This matches what ``#pragma pack(n)`` does in MSVC.
675+
672676
It is also possible to set a minimum alignment for how the subclass itself is packed in the
673677
same way ``#pragma align(n)`` works in MSVC.
674678
This can be achieved by specifying a ::attr:`~Structure._align_` class attribute
@@ -2540,6 +2544,31 @@ fields, or any other data types containing pointer type fields.
25402544
the structure when being packed or unpacked to/from memory.
25412545
Setting this attribute to 0 is the same as not setting it at all.
25422546

2547+
.. attribute:: _layout_
2548+
2549+
An optional string naming the struct/union layout. It can currently
2550+
be set to:
2551+
2552+
- ``"ms"``: the layout used by the Microsoft compiler (MSVC).
2553+
On GCC and Clang, this layout can be selected with
2554+
``__attribute__((ms_struct))``.
2555+
- ``"gcc-sysv"``: the layout used by GCC with the System V or “SysV-like”
2556+
data model, as used on Linux and macOS.
2557+
With this layout, :attr:`~Structure._pack_` must be unset or zero.
2558+
2559+
If not set explicitly, ``ctypes`` will use a default that
2560+
matches the platform conventions. This default may change in future
2561+
Python releases (for example, when a new platform gains official support,
2562+
or when a difference between similar platforms is found).
2563+
Currently the default will be:
2564+
2565+
- On Windows: ``"ms"``
2566+
- When :attr:`~Structure._pack_` is specified: ``"ms"``
2567+
- Otherwise: ``"gcc-sysv"``
2568+
2569+
:attr:`!_layout_` must already be defined when
2570+
:attr:`~Structure._fields_` is assigned, otherwise it will have no effect.
2571+
25432572
.. attribute:: _anonymous_
25442573

25452574
An optional sequence that lists the names of unnamed (anonymous) fields.

Doc/whatsnew/3.13.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,18 @@ copy
662662
any user classes which define the :meth:`!__replace__` method.
663663
(Contributed by Serhiy Storchaka in :gh:`108751`.)
664664

665+
ctypes
666+
------
667+
668+
* The layout of :ref:`bit fields <ctypes-bit-fields-in-structures-unions>` in
669+
:class:`~ctypes.Structure` and :class:`~ctypes.Union` was improved to better
670+
match platform defaults (GCC/Clang or MSC). In particular, fields no longer
671+
overlap.
672+
(Contributed by Matthias Görgens in :gh:`97702`.)
673+
* A :attr:`ctypes.Structure._layout_` class attribute can be set
674+
to help match a non-default ABI.
675+
(Contributed by Petr Viktorin in :gh:`97702`.)
676+
665677
dbm
666678
---
667679

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ struct _Py_global_strings {
256256
STRUCT_FOR_ID(_initializing)
257257
STRUCT_FOR_ID(_io)
258258
STRUCT_FOR_ID(_is_text_encoding)
259+
STRUCT_FOR_ID(_layout_)
259260
STRUCT_FOR_ID(_length_)
260261
STRUCT_FOR_ID(_limbo)
261262
STRUCT_FOR_ID(_lock_unlock_module)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)