【问题标题】:Boost Python 1.48 fails when exporting 32 bit enum导出 32 位枚举时,Boost Python 1.48 失败
【发布时间】:2015-10-15 11:06:26
【问题描述】:

较新版本的 Boost Python 是否支持从 C++ 导出完整的 32 位枚举?我正在使用 1.48 并且最多可以导出 30 位,但是当我尝试导出 32 位数字时,由于“访问冲突读取位置 0x00000001”每次都失败。深入研究 enum.cpp 文件,似乎在创建对象 x 时,它将字节 20 设置为 1,这导致失败,当它稍后尝试在 p->name 存在之前递减它时。我只需要升级到较新版本的 boost python 还是无法导出完整的 32 位数字?感谢您的意见!

【问题讨论】:

    标签: python c++ boost enums


    【解决方案1】:

    编辑:由 Tigger 在工作中发现,在此记录以供后人使用:

    问题在于 enum_object 结构的定义。 base_object 中的底层数字存储允许 15 位数字(作为 short)或 30 位数字(作为 int)粒度,但 base_object 仅包含足够的空间用于 2x 15 位数字或 1x 30 位数字。当存储大于 30 位的枚举值时,编码需要 3 个短或 2 个整数,具体取决于编译的格式。结果是名称成员占用了额外数字存储所需的空间。引用递减失败,因为值放置在 name 成员期望的位置。

    解决方案是在 name 成员之前添加 至少 32 位填充以处理 32 位枚举值。如果在遥远的将来需要 64 位枚举,则应添加 2 个填充字。

    struct enum_object
    {
    #if PY_VERSION_HEX >= 0x03000000
       PyLongObject base_object;
    #else
       PyIntObject base_object;
    #endif
       // ADD PADDING HERE TO FIX ALIGNMENT ISSUE
       PyObject* name;
    };
    

    结束编辑

    TL/DR:根本错误要么在转换中,要么在通过 enum_base::add_value 函数的堆栈变量进行的假定对象对齐中,但最简单的方法可能是单步执行转换器以查看值是否被损坏某种程度上来说。我会尝试的另一个实验是交换 .value 调用的顺序(这可能有助于确定是否存在与堆栈相关的问题)。

    详细信息: enum_base::add_value 函数在 1.48 和 1.58(最新)之间没有变化。此外,基于 python::api::object 类和 object_base_initializer 模板的显式转换“(*this)(value)”似乎也没有改变。我没有进一步遍历 object_base 构造函数来查看那里是否有任何变化;我建议使用有问题的值逐步完成转换序列,以查看高两位是否发生任何异常(我不确定您会在那里找到任何东西,但值得检查)。

    请记住,转换后的值随后会复制到堆栈“object x = (this)(value);”并且 enum_object p 的向下转换覆盖了一个大于 x.ptr() 引用的对象(即 m_ptr 成员)的对象。我现在不确定 m_p​​tr 是堆栈还是堆(没有遍历这些细节),但无论哪种方式,如果 p 现在覆盖陈旧或未初始化的内存,那么 p->name 处的引用减量将失败,如果它没有指向有效内存(如您所见)。

    我不确定 p->name 引用递减是否必要(对象生存期是本地的)...我得再考虑一下。我们可以在星期一讨论更多......这是一个周末......休息一下(我应该谈谈!)

    void enum_base::add_value(char const* name_, long value)
    {
        // Convert name to Python string
        object name(name_);
    
        // Create a new enum instance by calling the class with a value
        object x = (*this)(value);
    
        // Store the object in the enum class
        (*this).attr(name_) = x;
    
        dict d = extract<dict>(this->attr("values"))();
        d[value] = x;
    
        // Set the name field in the new enum instanec
        enum_object* p = downcast<enum_object>(x.ptr());
        Py_XDECREF(p->name);
        p->name = incref(name.ptr());
    
        dict names_dict = extract<dict>(this->attr("names"))();
        names_dict[x.attr("name")] = x;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-27
      • 2012-02-03
      • 1970-01-01
      • 2013-05-07
      • 1970-01-01
      • 1970-01-01
      • 2021-09-26
      • 1970-01-01
      • 2014-05-24
      相关资源
      最近更新 更多