EDIT:由 Tigger 在工作中发现,在此记录以供后代使用:
问题在于 enum_object 结构的定义。 base_object 中的底层数字存储允许 15 位数字(作为 Shorts)或 30 位数字(作为 int)粒度,但 base_object 仅包含足够的空间用于 2x 15 位数字或 1x 30 位数字。当存储 > 30 位枚举值时,编码需要 3 个短整型或 2 个整型,具体取决于编译的格式。结果是名称成员占用了额外数字存储所需的空间。引用递减失败,因为该值被放置在名称成员期望的位置。
解决方案是添加at least名称成员之前的 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;
};
END EDIT
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;
}