Commit d751470d authored by Rudi Chen's avatar Rudi Chen

Handle edge case with C extension metaclasses.

If both a metaclass and an instance of it are defined in C extensions,
the metaclass doesn't have attrs_offset != 0 or tp_dictoffset != 0
which causes the call to PyType_Ready on the instance to fail.
parent bf585e2e
......@@ -3317,8 +3317,24 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
cls->gc_visit = &conservativeGCHandler;
cls->is_user_defined = true;
// this should get automatically initialized to 0 on this path:
assert(cls->attrs_offset == 0);
if (!cls->instancesHaveHCAttrs() && cls->tp_base) {
// These doesn't get copied in inherit_slots like other slots do.
if (cls->tp_base->instancesHaveHCAttrs()) {
cls->attrs_offset = cls->tp_base->attrs_offset;
}
// Example of when this code path could be reached and needs to be:
// If this class is a metaclass defined in a C extension, chances are that some of its
// instances may be hardcoded in the C extension as well. Those instances will call
// PyType_Ready and expect their class (this metaclass) to have a place to put attributes.
// e.g. CTypes does this.
bool is_metaclass = PyType_IsSubtype(cls, type_cls);
assert(!is_metaclass || cls->instancesHaveHCAttrs() || cls->instancesHaveDictAttrs());
} else {
// this should get automatically initialized to 0 on this path:
assert(cls->attrs_offset == 0);
}
if (Py_TPFLAGS_BASE_EXC_SUBCLASS & cls->tp_flags) {
exception_types.push_back(cls);
......
......@@ -197,7 +197,7 @@ public:
// Analogous to tp_dictoffset
// A class should have at most of one attrs_offset and tp_dictoffset be nonzero.
// (But having nonzero attrs_offset here would map to having nonzero tp_dictoffset in CPython)
const int attrs_offset;
int attrs_offset;
bool instancesHaveHCAttrs() { return attrs_offset != 0; }
bool instancesHaveDictAttrs() { return tp_dictoffset != 0; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment