python / python/cpython

ctypes.Structure superclass with bitfields do not parse properly when it doesn't end on a byte boundary

Abierto
#117,942 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

topic-ctypes type-bug
Lenguaje dominante
Python
Estrellas
77.2k
Forks
35.9k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug report

Bug description:

I am trying to extend a ctypes Structure in a subclass but am running into some issues. My parent class defines bitfields that are intended to be expanded in the child class to fill the byte boundary.

import ctypes

class Parent(ctypes.BigEndianStructure):
    _pack_ = 1
    _fields_ = [
        ("field1", ctypes.c_uint8, 8),
        ("field2", ctypes.c_uint8, 6),
    ]

class Child(Parent):
    _pack_ = 1
    _fields_ = [
        ("field3", ctypes.c_uint8, 2),  # fills the missing bits from the parent
        ("field4", ctypes.c_uint16, 16)
    ]

When I run the following to test, I am not getting the expected values.

data = b"\x12\x02\xAB\xCD\xEF"
child = Child.from_buffer_copy(data)

print(hex(child.field1))  # 0x12
print(hex(child.field2))  # 0x00
print(hex(child.field3))  # 0x02
print(hex(child.field4))  # 0xABCD
print(bytes(child))
0x12
0x0
0x2
0xcdef   <--- we're missing the 3rd byte 0xAB, and shouldn't have 0xEF
b'\x12\x02\xab\xcd\xef'

I only have 4 bytes defined in the structure, but when trying to supply data with only 4 bytes, it throws an error

    child = Child.from_buffer_copy(data)
ValueError: Buffer size too small (4 instead of at least 5 bytes)

When combining into just one struct it seems to work fine

class Combined(ctypes.BigEndianStructure):
    _pack_ = 1
    _fields_ = [
        ("field1", ctypes.c_uint8, 8),
        ("field2", ctypes.c_uint8, 6),
        ("field3", ctypes.c_uint8, 2),
        ("field4", ctypes.c_uint16, 16)
    ]

combined = Combined.from_buffer_copy(data)
print(hex(combined.field1))  # 0x12
print(hex(combined.field2))  # 0x00
print(hex(combined.field3))  # 0x02
print(hex(combined.field4))  # 0xAB
print(bytes(combined))
0x12
0x0
0x2
0xabcd
b'\x12\x02\xab\xcd'

and adjusting the sizes of the bitfields in the parent/child classes seems to change the behavior

class Parent(ctypes.BigEndianStructure):
    _pack_ = 1
    _fields_ = [
        ("field1", ctypes.c_uint8, 8),
        ("field2", ctypes.c_uint8, 4),
    ]

class Child(Parent):
    _pack_ = 1
    _fields_ = [
        ("field3", ctypes.c_uint8, 4),
        ("field4", ctypes.c_uint16, 16)
    ]
0x12
0x0
0xa
0xcdef
b'\x12\x02\xab\xcd\xef'
class Parent(ctypes.BigEndianStructure):
    _pack_ = 1
    _fields_ = [
        ("field1", ctypes.c_uint8, 8),
        ("field2", ctypes.c_uint8, 2),
    ]

class Child(Parent):
    _pack_ = 1
    _fields_ = [
        ("field3", ctypes.c_uint8, 6),
        ("field4", ctypes.c_uint16, 16)
    ]
0x12
0x0
0x2a
0xcdef
b'\x12\x02\xab\xcd\xef'
CPython versions tested on:

3.9, 3.11

Operating systems tested on:

Linux

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Empieza reproduciendo el comportamiento mediante la herencia de ctypes.BigEndianStructure y Child.from_buffer_copy(), comparando el layout de la subclase con la estructura Combined mostrada en el informe. Sigue cómo se calculan los campos de bits heredados y el tamaño resultante del búfer. Se considera terminado cuando la subclase consume el layout esperado de cuatro bytes y produce los mismos valores de campo y bytes que la estructura combinada.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
backend
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
35/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.