python / python/cpython

ctypes._CData.from_buffer does not inherit _b_base_

未关闭
#135,894 1 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

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. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

首先检查关联的 PR gh-152706,并运行提供的 ctypes 复现程序。然后检查 _CData.from_buffer 背后的实现及其现有测试;当结果对象的 b_base 所有权链符合文档所述的缓冲区所有权行为时,即视为完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
backend
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
描述清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。