python / python/cpython

ctypes._CData.from_buffer does not inherit _b_base_

オープン
#135,894 コメント 1 件 リアクション 1 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

docs topic-ctypes
主要言語
Python
スター
77.2k
フォーク
35.9k
PR マージ指標
PR 指標を取得中

説明

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

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、リンクされている PR gh-152706 を確認し、提供された ctypes 再現コードを実行します。次に、_CData.from_buffer の背後にある実装と既存のテストを調査します。完了条件は、結果として得られるオブジェクトの b_base 所有権チェーンが、文書化されたバッファ所有権の動作と一致することです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
backend
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。