Skip to content

c_uint32 bitfields break structures #68478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
RonyBatista mannequin opened this issue May 26, 2015 · 6 comments
Closed

c_uint32 bitfields break structures #68478

RonyBatista mannequin opened this issue May 26, 2015 · 6 comments
Labels
topic-ctypes type-bug An unexpected behavior, bug, or error

Comments

@RonyBatista
Copy link
Mannequin

RonyBatista mannequin commented May 26, 2015

BPO 24290
Nosy @ronaldoussoren, @ned-deily
Files
  • ctypesBug.py
  • 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 2015-05-26.19:02:48.705>
    labels = ['ctypes', 'type-bug']
    title = 'c_uint32 bitfields break structures'
    updated_at = <Date 2015-05-27.22:57:25.193>
    user = 'https://bugs.python.org/RonyBatista'

    bugs.python.org fields:

    activity = <Date 2015-05-27.22:57:25.193>
    actor = 'Rony Batista'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['ctypes']
    creation = <Date 2015-05-26.19:02:48.705>
    creator = 'Rony Batista'
    dependencies = []
    files = ['39508']
    hgrepos = []
    issue_num = 24290
    keywords = []
    message_count = 5.0
    messages = ['244125', '244126', '244127', '244132', '244223']
    nosy_count = 3.0
    nosy_names = ['ronaldoussoren', 'ned.deily', 'Rony Batista']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue24290'
    versions = ['Python 2.7']

    @RonyBatista
    Copy link
    Mannequin Author

    RonyBatista mannequin commented May 26, 2015

    ctypes Structures with c_uint32 bitfields have strange behaviour on OS X.

    In the attached code when the field "number" is set, it changes the whole 32 bits, even thou its meant to be 23 bits.

    The behavior is unexpected in:
    OS X: Python 2.7.9

    The behavior is as expected in the following environments:
    Windows: python 2.7.9
    Ubuntu: python 2.7.6

    @RonyBatista RonyBatista mannequin added topic-ctypes type-bug An unexpected behavior, bug, or error labels May 26, 2015
    @ronaldoussoren
    Copy link
    Contributor

    You forgot to actually attach the code.

    @RonyBatista
    Copy link
    Mannequin Author

    RonyBatista mannequin commented May 26, 2015

    Silly me, Heres the code.

    @ned-deily
    Copy link
    Member

    Without diving into the details of your test program, I get the same results on a 64-bit Debian Python 2.7.9 as with a 64-bit OS X 2.7.10:

    c_uint32 TESTS:
    Class Name exponent number Sign float binary repr
    IEEE754Float_u ('-0x7b', '0xbeb2aL', 0L, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    IEEE754Float_u ('-0x7b', '0xbeb2aL', 0L, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    AN575Float_uint ('0x0', '0xbeb2a', 0L, 1.094551427887186e-39, ['0x0', '0xb', '0xeb', '0x2a'])
    AN575Float_uint ('0x0', '0xbeb2a', 0L, 1.094551427887186e-39, ['0x0', '0xb', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 0L, 1.094551427887186e-39, ['0x85', '0xb', '0xeb', '0x2a'])
    IEEE754Float_u ('-0x7b', '0xbeb2aL', 1L, -69.95930480957031, ['0xc2', '0x8b', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 1L, 1.094551427887186e-39, ['0x85', '0x8b', '0xeb', '0x2a'])

    But using the same OS X 2.7.10 in 32-bit mode, I get:

    c_uint32 TESTS:
    Class Name exponent number Sign float binary repr
    IEEE754Float_u ('-0x7b', '0xbeb2aL', 0L, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    IEEE754Float_u ('-0x7b', '0xbeb2aL', 0L, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 0L, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 0L, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 0L, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    IEEE754Float_u ('-0x7b', '0xbeb2aL', 1L, -69.95930480957031, ['0xc2', '0x8b', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 1L, -69.95930480957031, ['0x85', '0x8b', '0xeb', '0x2a'])

    @RonyBatista
    Copy link
    Mannequin Author

    RonyBatista mannequin commented May 27, 2015

    Well, looks like the issue is with 64 bit mode then.

    For the first 5 cases the right answer is 69.95930480957031, and for the last 2 its -69.95930480957031. The results for the 32 bit mode are all correct.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    @encukou
    Copy link
    Member

    encukou commented May 13, 2025

    Should be fixed in #97702.

    Code updated for Python 3:

    __author__ = 'rony'
    
    from ctypes import BigEndianStructure
    from ctypes import sizeof, memmove, addressof
    from ctypes import c_int32, c_uint32
    from struct import pack, unpack
    
    
    class BigEndianByteStructure(BigEndianStructure):
        # https://wiki.python.org/moin/ctypes
        @classmethod
        def from_bytes(cls, ibytes):
            return_val = cls()
            if len(ibytes) != sizeof(return_val):
                raise ValueError(
                    '{0} Cannot unpack {2} bytes, it should be {1} bytes'.format(cls.__name__, sizeof(return_val),
                                                                                 len(ibytes)))
    
            memmove(addressof(return_val), ibytes, len(ibytes))
            return return_val
    
        @classmethod
        def from_structure(cls, original):
            return_val = cls()
            for field in return_val._fields_:
                try:
                    setattr(return_val, field[0], getattr(original, field[0]))
                except:
                    print( 'Attribute {0} not found in original'.format(field[0]))
    
            return return_val
    
    
    # POSITIVE
    # IEEE754 HEX    0x428beb2a
    # AN575 HEX      0x850beb2a
    
    # NEGATIVE
    # IEEE754 HEX    0xc28beb2a
    # AN575 HEX      0x858beb2a
    
    class IEEE754Float(BigEndianByteStructure):
        _pack_ = 1
        _fields_ = [('sign', c_int32, 1),
                    ('exponent', c_int32, 8),
                    ('number', c_int32, 23)]
    
        @classmethod
        def from_float(cls, f):
            return cls.from_bytes(pack('>f', f))
    
        def __float__(self):
            return unpack('>f', memoryview(self))[0]
    
        def debug(self):
            f = self
            return hex(f.exponent), hex(f.number), f.sign, float(f), [hex(b) for b in bytearray(f)]
    
    
    class AN575Float(BigEndianByteStructure):
        _pack_ = 1
        _fields_ = [('exponent', c_int32, 8),
                    ('sign', c_int32, 1),
                    ('number', c_int32, 23)]
    
        @classmethod
        def from_float(cls, f):
            return cls.from_structure(IEEE754Float.from_float(f))
    
        def __float__(self):
            a = IEEE754Float.from_structure(self)
            return float(a)
    
        def debug(self):
            f = self
            return hex(f.exponent), hex(f.number), f.sign, float(f), [hex(b) for b in bytearray(f)]
    
    
    class IEEE754Float_u(BigEndianByteStructure):
        _pack_ = 1
        _fields_ = [('sign', c_uint32, 1),
                    ('exponent', c_int32, 8),
                    ('number', c_uint32, 23)]
    
        @classmethod
        def from_float(cls, f):
            return cls.from_bytes(pack('>f', f))
    
        def __float__(self):
            return unpack('>f', memoryview(self))[0]
    
        def debug(self):
            f = self
            return hex(f.exponent), hex(f.number), f.sign, float(f), [hex(b) for b in bytearray(f)]
    
    
    class AN575Float_uint(BigEndianByteStructure):
        _pack_ = 1
        _fields_ = [('exponent', c_int32, 8),
                    ('sign', c_uint32, 1),
                    ('number', c_int32, 23)]
    
        @classmethod
        def from_float(cls, f):
            return cls.from_structure(IEEE754Float_u.from_float(f))
    
        def __float__(self):
            a = IEEE754Float_u.from_structure(self)
            return float(a)
    
        def debug(self):
            f = self
            return hex(f.exponent), hex(f.number), f.sign, float(f), [hex(b) for b in bytearray(f)]
    
    
    print ('\n', 'c_int32 TESTS:')
    print ('Class Name\t\t', 'exponent', '\tnumber', '\tSign', '\tfloat', '\t\t\t\t', 'binary repr')
    f = IEEE754Float.from_float(69.9593067)
    print (type(f).__name__, f.debug())
    
    f = IEEE754Float.from_bytes(b'\x42\x8b\xeb\x2a')
    print (type(f).__name__, f.debug())
    
    f = AN575Float.from_float(69.9593067)
    print (type(f).__name__, f.debug())
    
    f = AN575Float.from_structure(IEEE754Float.from_float(69.9593067))
    print (type(f).__name__, f.debug())
    
    f = AN575Float.from_bytes(b'\x85\x0b\xeb\x2a')
    print (type(f).__name__, f.debug())
    
    f = IEEE754Float.from_bytes(b'\xc2\x8b\xeb\x2a')
    print (type(f).__name__, f.debug())
    
    f = AN575Float.from_bytes(b'\x85\x8b\xeb\x2a')
    print (type(f).__name__, f.debug())
    
    print ('\n', 'c_uint32 TESTS:')
    print ('Class Name\t\t', 'exponent', '\tnumber', '\tSign', '\tfloat', '\t\t\t\t', 'binary repr')
    f = IEEE754Float_u.from_float(69.9593067)
    print (type(f).__name__, f.debug())
    
    f = IEEE754Float_u.from_bytes(b'\x42\x8b\xeb\x2a')
    print (type(f).__name__, f.debug())
    
    f = AN575Float_uint.from_float(69.9593067)
    print (type(f).__name__, f.debug())
    
    f = AN575Float_uint.from_structure(IEEE754Float.from_float(69.9593067))
    print (type(f).__name__, f.debug())
    
    f = AN575Float_uint.from_bytes(b'\x85\x0b\xeb\x2a')
    print (type(f).__name__, f.debug())
    
    f = IEEE754Float_u.from_bytes(b'\xc2\x8b\xeb\x2a')
    print (type(f).__name__, f.debug())
    
    f = AN575Float_uint.from_bytes(b'\x85\x8b\xeb\x2a')
    print (type(f).__name__, f.debug())

    Result (same on 64- and 32-bit OS):

    
     c_int32 TESTS:
    Class Name		 exponent 	number 	Sign 	float 				 binary repr
    IEEE754Float ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    IEEE754Float ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    AN575Float ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    AN575Float ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    AN575Float ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    IEEE754Float ('-0x7b', '0xbeb2a', -1, -69.95930480957031, ['0xc2', '0x8b', '0xeb', '0x2a'])
    AN575Float ('-0x7b', '0xbeb2a', -1, -69.95930480957031, ['0x85', '0x8b', '0xeb', '0x2a'])
    
     c_uint32 TESTS:
    Class Name		 exponent 	number 	Sign 	float 				 binary repr
    IEEE754Float_u ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    IEEE754Float_u ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x42', '0x8b', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 0, 69.95930480957031, ['0x85', '0xb', '0xeb', '0x2a'])
    IEEE754Float_u ('-0x7b', '0xbeb2a', 1, -69.95930480957031, ['0xc2', '0x8b', '0xeb', '0x2a'])
    AN575Float_uint ('-0x7b', '0xbeb2a', 1, -69.95930480957031, ['0x85', '0x8b', '0xeb', '0x2a'])
    

    @encukou encukou closed this as completed May 13, 2025
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    topic-ctypes type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    4 participants