python / python/cpython

ctypes._CData.from_buffer does not inherit _b_base_

Offen
#135,894 1 Kommentar 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

docs topic-ctypes
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Continuing work from #135669, I have noticed another inconsistency.

from_buffer docs say:

This method returns a ctypes instance that shares the buffer of the source object.

_b_base_ docs say:

The _b_base_ read-only member is the root ctypes object that owns the memory block.

So, I assumed that, when passing a ctypes object as source to from_buffer, the _b_base_ from the resulting ctypes object would be inherited from source, however that is not the case.

To better visualize the issue, lets consider this code:

import ctypes

bindata = bytearray([
    0, 0, # [0].offset
    2, 0, # [0].variant
    8, 0, # [1].offset
    1, 0, # [1].variant

    # dynamic_part
    1, 2, 3, 4,
    5, 6,

    0, 0,

    9, 8, 7, 6,
])

class A(ctypes.Structure):
    _fields_ = [
        ("foo", ctypes.c_int),
    ]
class B(ctypes.Structure):
    _fields_ = [
        ("bar", ctypes.c_byte * 6),
    ]

class Message(ctypes.Structure):
    _fields_ = [
        ("offset", ctypes.c_uint16),
        ("variant", ctypes.c_uint16),
    ]

    variants = {
        1: A,
        2: B,
    }

    def get(self):
        root = self._b_base_._b_base_
        _type = self.variants[self.variant]

        try:
            return _type.from_buffer(root.dynamic_part, self.offset)
        except ValueError as e:
            e.add_note(f"Invalid data offset={self.offset} variant={self.variant}")
            raise

class FinalData(ctypes.Structure):
    _fields_ = [
        ("messages", Message * 2),
        ("dynamic_part", ctypes.c_ubyte * 12),
    ]

x = FinalData.from_buffer(bindata)

print(x)
print(x.dynamic_part._b_base_)

a = x.messages[1].get()
b = x.messages[0].get()
print(a)
print(a._b_base_)
print(b)
print(b._b_base_)

I expected the a._b_base_ and b._b_base_ would be <__main__.FinalData object at 0x7fbee293d3d0>, like x.dynamic_part._b_base_, instead it is None.

Linked PRs
  • gh-152706

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit der Prüfung des verknüpften PR gh-152706 und führe den bereitgestellten ctypes-Reproducer aus. Untersuche anschließend die Implementierung hinter _CData.from_buffer und die vorhandenen Tests; als erledigt gilt die Aufgabe, wenn die b_base-Besitzkette des resultierenden Objekts dem dokumentierten Verhalten des Buffer-Besitzes entspricht.

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
Klar beschrieben
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.