python / cpython

The Python programming language
https://www.python.org
Other
63.14k stars 30.23k forks source link

Bitfield Union does not work for bit widths greater than 8 bits #83588

Open 244502f1-01b3-4087-ad3b-4105e5a66d11 opened 4 years ago

244502f1-01b3-4087-ad3b-4105e5a66d11 commented 4 years ago
BPO 39407
Nosy @vsajip, @amauryfa, @abalkin, @meadori
Files
  • python_struct_union_bug.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: ```python assignee = None closed_at = None created_at = labels = ['ctypes', 'type-bug', '3.7'] title = 'Bitfield Union does not work for bit widths greater than 8 bits' updated_at = user = 'https://bugs.python.org/jschulte' ``` bugs.python.org fields: ```python activity = actor = 'ammar2' assignee = 'none' closed = False closed_date = None closer = None components = ['ctypes'] creation = creator = 'jschulte' dependencies = [] files = ['48856'] hgrepos = [] issue_num = 39407 keywords = [] message_count = 1.0 messages = ['360372'] nosy_count = 5.0 nosy_names = ['vinay.sajip', 'amaury.forgeotdarc', 'belopolsky', 'meador.inge', 'jschulte'] pr_nums = [] priority = 'normal' resolution = None stage = None status = 'open' superseder = None type = 'behavior' url = 'https://bugs.python.org/issue39407' versions = ['Python 3.7'] ```

    244502f1-01b3-4087-ad3b-4105e5a66d11 commented 4 years ago

    Creating a Bitfield from a ctypes union and structure results in unexpected behaviour. It seems when you set the bit-width of a structure field to be greater than 8 bits it results in the subsequent bits being set to zero.

    class BitFieldStruct(ctypes.LittleEndianStructure):
        _fields_ = [
            ("long_field", C_UINT32, 29),
            ("short_field_0", C_UINT8, 1),
            ("short_field_1", C_UINT8, 1),
            ("short_field_2", C_UINT8, 1),
        ]
    
    class BitField(ctypes.Union):
        _anonymous_ = ("fields",)
        _fields_ = [
            ("fields", BitFieldStruct),
            ("as32bit", C_UINT32)
        ]
    
    def test_bit_field_union():
        f = BitField()
        f.as32bit = int.from_bytes([255, 255, 255, 255], byteorder='little')
    assert f.long_field == int.from_bytes([255, 255, 255, 31], byteorder='little')
    assert f.short_field_0 == 1
    assert f.short_field_1 == 1
    assert f.short_field_2 == 1
    test_bit_field_union()  # this call will fail with an assertion error

    Equivalent C which does not fail https://rextester.com/FWV78514

    I'm running on Ubuntu 16.04 with python3.6 but I have tested on 3.5, 3.7 and on repl.it with the same behaviour.

    It seems as though setting any of the struct fields to be greater than 8 bit width results in any of the following fields being set to zero.

    encukou commented 1 month ago

    Let's use this issue to track matching ctypes unions with bitfields to what C compilers do.

    Getting the details right -- and testing them -- will be a bit complicated, so it deserves a separate issue. Apparently, the MS compiler and GCC's __attribute__((ms_struct)) don't always agree on the alignment of such unions.