summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2022-08-03 17:56:24 (GMT)
committerGitHub <noreply@github.com>2022-08-03 17:56:24 (GMT)
commit906e4509328917fe9951f85457897f6a841e0529 (patch)
tree0ee26881b28d07bc0ec00ae72e3af3f8f134f8a6 /Objects
parent89f52293281b6efc4ef666ef25e677683821f4b9 (diff)
downloadcpython-906e4509328917fe9951f85457897f6a841e0529.zip
cpython-906e4509328917fe9951f85457897f6a841e0529.tar.gz
cpython-906e4509328917fe9951f85457897f6a841e0529.tar.bz2
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.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index d33befc0..1980fcb 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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;
}