python / cpython

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

ctypes: bitfield lost data with union on linux platform #95496

Open px528 opened 2 years ago

px528 commented 2 years ago

below example is simple and can be reproduced.

from ctypes import Structure,Union
from ctypes import alignment,sizeof
from ctypes import c_int8,c_int16,c_int32,c_int64
from ctypes import c_uint8,c_uint16,c_uint32,c_uint64

class sub_type(Structure):
    _fields_ = [
    ('a',c_uint8,4),
    ('b',c_uint8,4),
    ('c',c_uint16,10),
    ('d',c_uint16,10),
    ('e',c_uint8,1),
    ('f',c_uint8,1),
    ('g',c_uint8,1),
    ]

class main_type(Union):
    byte_length = sizeof(sub_type)
    _fields_ = [
                ("data",    sub_type),
                ("asbytes",  c_uint8*byte_length),
    ]

a=main_type(data=sub_type(e=1,f=1,g=1))
print(list(a.asbytes))

#on windows, print value is correct
#[0, 0, 0, 0, 0, 0, 7, 0]

#on linux, the value is wrong at all. the length is correct, but value is wrong.
#[0, 0, 0, 0, 0, 0]
korjaa commented 2 years ago

I get similar error without unions. Below is a test snippet that passes on Windows but fails on Ubuntu WSL2.

import ctypes

for field_width in range(32, 1, -1):
    class TestStruct(ctypes.Structure):
        _fields_ = [
            ("Field1", ctypes.c_uint32, field_width),
            ("Field2", ctypes.c_uint8, 8)
        ]

    cmd = TestStruct()
    cmd.Field2 = 1
    if cmd.Field2 != 1:
        raise RuntimeError(f"{field_width=}, {cmd.Field2=} != 1")

print("All good")

I get following output in WSL2 Ubuntu

$ python --version
Python 3.8.10

$ python -c 'import ctypes; print(ctypes.__version__)'
1.1.0

$ python ctypes_test.py
Traceback (most recent call last):
  File "ctypes_test.py", line 13, in <module>
    raise RuntimeError(f"{field_width=}, {cmd.Field2=} != 1")
RuntimeError: field_width=24, cmd.Field2=0 != 1

I tried Python 3.9 on WSL2 Ubuntu too with same result.

px528 commented 2 years ago

Your E-mail has been received and I will reply as soon as possible