Skip to content

Adding a ctypes.Union to a ctypes.BigEndianStructure results in an error #87239

Closed
@MrSurly

Description

@MrSurly
mannequin
BPO 43073
Nosy @MrSurly

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2021-01-30.04:38:58.603>
labels = ['ctypes', '3.8']
title = 'Adding a ctypes.Union to a ctypes.BigEndianStructure results in an error'
updated_at = <Date 2021-11-07.14:24:54.167>
user = 'https://github.com/MrSurly'

bugs.python.org fields:

activity = <Date 2021-11-07.14:24:54.167>
actor = 'rindeal'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['ctypes']
creation = <Date 2021-01-30.04:38:58.603>
creator = 'MrSurly'
dependencies = []
files = []
hgrepos = []
issue_num = 43073
keywords = []
message_count = 2.0
messages = ['385970', '405906']
nosy_count = 2.0
nosy_names = ['MrSurly', 'rindeal']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue43073'
versions = ['Python 3.8']

Activity

MrSurly

MrSurly commented on Jan 30, 2021

@MrSurly
MannequinAuthor

Placing a ctypes.Union inside of a ctypes.BigEndianStructure results in "TypeError: This type does not support other endian". I believe this is a similar problem to issue bpo-4376 (https://bugs.python.org/issue4376)

Minimum repro test case:

import ctypes as ct

class U(ct.Union):
    _pack_=True
    _fields_=[
        ('a', ct.c_int),
        ('b', ct.c_int),
    ]

class S(ct.BigEndianStructure):
    _pack_=True
    _fields_=[
        ('x', ct.c_int),
        ('y', U),
    ]

I believe the fix is similar to that issue, though I admit I don't know enough about this code to be sure.

diff --git a/Lib/ctypes/_endian.py b/Lib/ctypes/_endian.py
index 37444bd6a7..525c5e58c9 100644
--- a/Lib/ctypes/_endian.py
+++ b/Lib/ctypes/_endian.py
@@ -18,6 +18,9 @@ def _other_endian(typ):
     # if typ is structure
     if issubclass(typ, Structure):
         return typ
+    # if typ is union:
+    if issubclass(typ, Union):
+        return typ
     raise TypeError("This type does not support other endian: %s" % typ)
 
 class _swapped_meta(type(Structure)):
rindeal

rindeal commented on Nov 7, 2021

@rindeal
Mannequin

I have created a workaround, since it might take years to fix this in master. Hope it'll come in useful.

For the example in https://bugs.python.org/issue43073#msg385970, but probably any combination of Unions and BigEndianStructures can be constructed this way.

class U_a(ct.BigEndianStructure):
    _pack_ = True
    _fields_ = [('a', ct.c_int)]

class U_b(ct.BigEndianStructure):
    _pack_ = True
    _fields_ = [('b', ct.c_int)]

class U(ct.Union):
    _pack_ = True
    _fields_ = [
        ('_a', U_a),
        ('_b', U_b),
    ]
    _anonymous_ = ['_a', '_b']

class _S_be_fields_only(ct.Structure):
    _pack_ = True
    _fields_ = [
        ('_x', ct.c_int),
        ('y', U),
    ]
class _S_2be_fields_only(ct.BigEndianStructure):
    _pack_ = True
    _fields_ = [
        ('x', ct.c_int),
        ('_y', ct.c_byte * ct.sizeof(U)),
    ]

class _S_U(ct.Union):
    _pack_ = True
    _fields_ = [
        ('_be_fields_only', _S_be_fields_only),
        ('_2be_fields_only', _S_2be_fields_only),
    ]
    _anonymous_ = [f[0] for f in _fields_]

class S(ct.Structure):
    _pack_ = True
    _fields_ = [('_s_u', _S_U)]
    _anonymous_ = [_fields_[0][0]]


issubclass(S, ct.Structure) == True
s = S(x=0x11223344, y=U(a=0xaabbccdd))
s.y.a == s.y.b
bytes(s).hex() == "11223344aabbccdd"
transferred this issue fromon Apr 10, 2022
encukou

encukou commented on May 13, 2025

@encukou
Member

This works in Python 3.11; presumably due to #25480.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Adding a ctypes.Union to a ctypes.BigEndianStructure results in an error · Issue #87239 · python/cpython

      Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

      Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant