GH-92678: Fix tp_dictoffset inheritance. (GH-95596)

* Add test for inheriting explicit __dict__ and weakref.

* Restore 3.10 behavior for multiple inheritance of C extension classes that store their dictionary at the end of the struct.
This commit is contained in:
Mark Shannon 2022-08-03 18:56:24 +01:00 committed by GitHub
parent 89f5229328
commit 906e450932
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 3 deletions

View file

@ -2316,6 +2316,11 @@ best_base(PyObject *bases)
return base;
}
#define ADDED_FIELD_AT_OFFSET(name, offset) \
(type->tp_ ## name && (base->tp_ ##name == 0) && \
type->tp_ ## name + sizeof(PyObject *) == (offset) && \
type->tp_flags & Py_TPFLAGS_HEAPTYPE)
static int
extra_ivars(PyTypeObject *type, PyTypeObject *base)
{
@ -2328,10 +2333,18 @@ extra_ivars(PyTypeObject *type, PyTypeObject *base)
return t_size != b_size ||
type->tp_itemsize != base->tp_itemsize;
}
if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 &&
type->tp_weaklistoffset + sizeof(PyObject *) == t_size &&
type->tp_flags & Py_TPFLAGS_HEAPTYPE)
/* Check for __dict__ and __weakrefs__ slots in either order */
if (ADDED_FIELD_AT_OFFSET(weaklistoffset, t_size)) {
t_size -= sizeof(PyObject *);
}
if ((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0 &&
ADDED_FIELD_AT_OFFSET(dictoffset, t_size)) {
t_size -= sizeof(PyObject *);
}
/* Check __weakrefs__ again, in case it precedes __dict__ */
if (ADDED_FIELD_AT_OFFSET(weaklistoffset, t_size)) {
t_size -= sizeof(PyObject *);
}
return t_size != b_size;
}