python / python/cpython

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

Ouverte
#117,942 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

topic-ctypes type-bug
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par reproduire le comportement via l’héritage de ctypes.BigEndianStructure et Child.from_buffer_copy(), en comparant la disposition de la sous-classe avec la structure Combined présentée dans le rapport. Suivez la manière dont les champs de bits hérités et la taille de tampon qui en résulte sont calculés. C’est terminé lorsque la sous-classe utilise la disposition attendue de quatre octets et produit les mêmes valeurs de champs et les mêmes octets que la structure combinée.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
backend
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.