首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C-API:分配“PyTypeObject-扩展”

C-API:分配“PyTypeObject-扩展”
EN

Stack Overflow用户
提问于 2014-11-16 19:18:16
回答 2查看 420关注 0票数 0

我在PyCXX中发现了一些可能是错误的代码。

它真的是一个bug吗?如果是的话,有什么正确的方法来解决它呢?

以下是问题所在:

代码语言:javascript
复制
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的表示)。

异种为存储PyObject分配内存

然后,代码将这个指针输入到一个PythonClassInstance,并声明为一个额外的4(或8?)它不拥有的字节!

然后将这个额外的内存设置为0。

这看起来很危险,我很惊讶这个bug竟然没有被注意到。风险是将来的一些对象将被放置在这个位置(这意味着存储ExtObjBase*)。

怎么修呢?

代码语言:javascript
复制
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硝酸盐“,并且:

如果类型的tp_itemsize为非零,则应将对象的ob_size字段初始化为nitems,而分配的内存块的长度应为tp_basicsize + nitemstp_itemsize,舍入为相当大的倍数(无效);否则,不使用nitems,块的长度应为tp_basicsize。

所以看起来我应该设置:

代码语言:javascript
复制
table->tp_itemsize = sizeof(void*);
:
PyObject* tmp = subtype->tp_alloc(subtype,1);

编辑:刚试过这个,它会导致崩溃。

但文件接着又说:

不要使用此函数进行任何其他实例初始化,甚至不能分配额外的内存;这应该由tp_new来完成。

现在我不确定这段代码是属于tp_new还是tp_init。

相关信息:

Python中子类型的init

Python对象分配‏

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-18 15:37:58

实际上,这是一个(小/无害的) PyCXX中的bug

所以想把这个答案转换成一个评论,这是没有意义的,我不能授予绿色滴答的完成,所以我的评论。所以我得漫步才能符合条件。布莱。

票数 0
EN

Stack Overflow用户

发布于 2014-11-19 01:24:39

密码是正确的。

只要正确初始化扩展对象的PyTypeObject,它就可以工作。

基类tp_alloc接收subtype,因此它应该通过检查tp_basicsize成员来知道要分配多少内存。

这是一个常见的Python /API模式,如在教程中演示的那样。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26961000

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档