ctypes.Structure superclass with bitfields do not parse properly when it doesn't end on a byte boundary
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 77.2k
- Forks
- 36k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
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
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne damit, das Verhalten durch die Vererbung von ctypes.BigEndianStructure und Child.from_buffer_copy() zu reproduzieren, und vergleiche dabei das Layout der Unterklasse mit der im Bericht gezeigten Combined-Struktur. Verfolge, wie geerbte Bitfelder und die daraus resultierende Puffergröße berechnet werden. Als erledigt gilt die Aufgabe, wenn die Unterklasse das erwartete Layout von vier Bytes verwendet und dieselben Feldwerte und Bytes wie die kombinierte Struktur erzeugt.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- backend
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 35/100