C-API:分配“PyTypeObject-extension”
Posted
技术标签:
【中文标题】C-API:分配“PyTypeObject-extension”【英文标题】:C-API: Allocating "PyTypeObject-extension" 【发布时间】:2014-11-16 19:18:16 【问题描述】:我在 PyCXX 中发现了一些可能有问题的代码。
这是否确实是一个错误,如果是,修复它的正确方法是什么?
问题来了:
struct PythonClassInstance
PyObject_HEAD
ExtObjBase* m_pycxx_object;
:
:
table->tp_new = extension_object_new; // PyTypeObject
:
:
static PyObject* extension_object_new(
PyTypeObject* subtype, PyObject* args, PyObject* kwds )
PythonClassInstance* o = reinterpret_cast<PythonClassInstance *>
( subtype->tp_alloc(subtype,0) );
if( ! o )
return nullptr;
o->m_pycxx_object = nullptr;
PyObject* self = reinterpret_cast<PyObject* >( o );
return self;
现在 PyObject_HEAD 扩展为“PyObject ob_base;”,因此很明显 PythonClassInstance 简单地扩展了 PyObject 以包含一个额外的指针(它将指向 PyCXX 对此 PyObject 的表示)
tp_alloc 分配内存用于存储 PyObject
然后,代码将此指针类型转换为 PythonClassInstance,声明它不拥有的额外 4(或 8?)个字节!
然后它将这个额外的内存设置为 0。
这看起来很危险,我很惊讶这个错误竟然被忽视了。风险是一些未来的对象将被放置在这个位置(即存储 ExtObjBase*)。
如何解决?
PythonClassInstance foo;
PyObject* tmp = subtype->tp_alloc(subtype,0);
// !!! memcpy sizeof(PyObject) bytes starting from location tmp into location (void*)foo
但我想现在也许我需要释放 tmp,而且我认为我不应该像这样直接玩内存。我觉得它可能会危及 Python 的内存管理/垃圾收集内置机制。
另一种选择是,也许我可以说服 tp_alloc 分配 4 个额外字节(或者现在是 8 个;对于指针来说足够了)绕过 1 而不是 0。
文档说第二个参数是“Py_ssize_t nitems”并且:
如果类型的 tp_itemsize 不为零,则对象的 ob_size 字段 应该初始化为 nitems 和分配内存的长度 块应为 tp_basicsize + nitemstp_itemsize,四舍五入为 sizeof(void) 的倍数;否则,不使用 nitems 并且 块的长度应该是 tp_basicsize。
所以看起来我应该设置:
table->tp_itemsize = sizeof(void*);
:
PyObject* tmp = subtype->tp_alloc(subtype,1);
编辑:刚刚尝试过,它会导致崩溃
但是文档接着说:
不要使用这个函数做任何其他的实例初始化,不要 甚至分配额外的内存;这应该由 tp_new 完成。
现在我不确定这段代码是属于 tp_new 还是 tp_init。
相关:
Passing arguments to tp_new and tp_init from subtypes in Python C API
Python C-API Object Allocation
【问题讨论】:
【参考方案1】:代码是正确的。
只要扩展对象的 PyTypeObject 正确初始化,它就可以工作。
基类tp_alloc
接收subtype
,因此它应该通过检查tp_basicsize
成员来知道要分配多少内存。
这是tutorial 中演示的常见 Python C/API 模式。
【讨论】:
【参考方案2】:其实这是一个(轻微/无害的)bug in PyCXX
所以想将此答案转换为评论,这毫无意义我不能授予完成的绿色勾号,所以我发表评论。所以我必须漫步才能获得资格。呵呵。
【讨论】:
以上是关于C-API:分配“PyTypeObject-extension”的主要内容,如果未能解决你的问题,请参考以下文章
在 ubuntu 20.04 LTS 上使用 python Xlib 或 C-API 操作第二个(辅助)鼠标输入