编辑:由 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_ptr 是堆栈还是堆(没有遍历这些细节),但无论哪种方式,如果 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;
}