mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
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:
parent
89f5229328
commit
906e450932
4 changed files with 65 additions and 3 deletions
|
@ -619,6 +619,25 @@ class CAPITest(unittest.TestCase):
|
||||||
with self.assertRaisesRegex(TypeError, msg):
|
with self.assertRaisesRegex(TypeError, msg):
|
||||||
t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclassCustomNew)
|
t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclassCustomNew)
|
||||||
|
|
||||||
|
def test_multiple_inheritance_ctypes_with_weakref_or_dict(self):
|
||||||
|
|
||||||
|
class Both1(_testcapi.HeapCTypeWithWeakref, _testcapi.HeapCTypeWithDict):
|
||||||
|
pass
|
||||||
|
class Both2(_testcapi.HeapCTypeWithDict, _testcapi.HeapCTypeWithWeakref):
|
||||||
|
pass
|
||||||
|
|
||||||
|
for cls in (_testcapi.HeapCTypeWithDict, _testcapi.HeapCTypeWithDict2,
|
||||||
|
_testcapi.HeapCTypeWithWeakref, _testcapi.HeapCTypeWithWeakref2):
|
||||||
|
for cls2 in (_testcapi.HeapCTypeWithDict, _testcapi.HeapCTypeWithDict2,
|
||||||
|
_testcapi.HeapCTypeWithWeakref, _testcapi.HeapCTypeWithWeakref2):
|
||||||
|
if cls is not cls2:
|
||||||
|
class S(cls, cls2):
|
||||||
|
pass
|
||||||
|
class B1(Both1, cls):
|
||||||
|
pass
|
||||||
|
class B2(Both1, cls):
|
||||||
|
pass
|
||||||
|
|
||||||
def test_pytype_fromspec_with_repeated_slots(self):
|
def test_pytype_fromspec_with_repeated_slots(self):
|
||||||
for variant in range(2):
|
for variant in range(2):
|
||||||
with self.subTest(variant=variant):
|
with self.subTest(variant=variant):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Restore the 3.10 behavior for multiple inheritance of C extension classes
|
||||||
|
that store their dictionary at the end of the struct.
|
|
@ -737,6 +737,14 @@ static PyType_Spec HeapCTypeWithDict_spec = {
|
||||||
HeapCTypeWithDict_slots
|
HeapCTypeWithDict_slots
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PyType_Spec HeapCTypeWithDict2_spec = {
|
||||||
|
"_testcapi.HeapCTypeWithDict2",
|
||||||
|
sizeof(HeapCTypeWithDictObject),
|
||||||
|
0,
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||||
|
HeapCTypeWithDict_slots
|
||||||
|
};
|
||||||
|
|
||||||
static struct PyMemberDef heapctypewithnegativedict_members[] = {
|
static struct PyMemberDef heapctypewithnegativedict_members[] = {
|
||||||
{"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
|
{"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
|
||||||
{"__dictoffset__", T_PYSSIZET, -(Py_ssize_t)sizeof(void*), READONLY},
|
{"__dictoffset__", T_PYSSIZET, -(Py_ssize_t)sizeof(void*), READONLY},
|
||||||
|
@ -796,6 +804,14 @@ static PyType_Spec HeapCTypeWithWeakref_spec = {
|
||||||
HeapCTypeWithWeakref_slots
|
HeapCTypeWithWeakref_slots
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PyType_Spec HeapCTypeWithWeakref2_spec = {
|
||||||
|
"_testcapi.HeapCTypeWithWeakref2",
|
||||||
|
sizeof(HeapCTypeWithWeakrefObject),
|
||||||
|
0,
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||||
|
HeapCTypeWithWeakref_slots
|
||||||
|
};
|
||||||
|
|
||||||
PyDoc_STRVAR(heapctypesetattr__doc__,
|
PyDoc_STRVAR(heapctypesetattr__doc__,
|
||||||
"A heap type without GC, but with overridden __setattr__.\n\n"
|
"A heap type without GC, but with overridden __setattr__.\n\n"
|
||||||
"The 'value' attribute is set to 10 in __init__ and updated via attribute setting.");
|
"The 'value' attribute is set to 10 in __init__ and updated via attribute setting.");
|
||||||
|
@ -919,6 +935,12 @@ _PyTestCapi_Init_Heaptype(PyObject *m) {
|
||||||
}
|
}
|
||||||
PyModule_AddObject(m, "HeapCTypeWithDict", HeapCTypeWithDict);
|
PyModule_AddObject(m, "HeapCTypeWithDict", HeapCTypeWithDict);
|
||||||
|
|
||||||
|
PyObject *HeapCTypeWithDict2 = PyType_FromSpec(&HeapCTypeWithDict2_spec);
|
||||||
|
if (HeapCTypeWithDict2 == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyModule_AddObject(m, "HeapCTypeWithDict2", HeapCTypeWithDict2);
|
||||||
|
|
||||||
PyObject *HeapCTypeWithNegativeDict = PyType_FromSpec(&HeapCTypeWithNegativeDict_spec);
|
PyObject *HeapCTypeWithNegativeDict = PyType_FromSpec(&HeapCTypeWithNegativeDict_spec);
|
||||||
if (HeapCTypeWithNegativeDict == NULL) {
|
if (HeapCTypeWithNegativeDict == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -931,6 +953,12 @@ _PyTestCapi_Init_Heaptype(PyObject *m) {
|
||||||
}
|
}
|
||||||
PyModule_AddObject(m, "HeapCTypeWithWeakref", HeapCTypeWithWeakref);
|
PyModule_AddObject(m, "HeapCTypeWithWeakref", HeapCTypeWithWeakref);
|
||||||
|
|
||||||
|
PyObject *HeapCTypeWithWeakref2 = PyType_FromSpec(&HeapCTypeWithWeakref2_spec);
|
||||||
|
if (HeapCTypeWithWeakref2 == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyModule_AddObject(m, "HeapCTypeWithWeakref2", HeapCTypeWithWeakref2);
|
||||||
|
|
||||||
PyObject *HeapCTypeWithBuffer = PyType_FromSpec(&HeapCTypeWithBuffer_spec);
|
PyObject *HeapCTypeWithBuffer = PyType_FromSpec(&HeapCTypeWithBuffer_spec);
|
||||||
if (HeapCTypeWithBuffer == NULL) {
|
if (HeapCTypeWithBuffer == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -2316,6 +2316,11 @@ best_base(PyObject *bases)
|
||||||
return base;
|
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
|
static int
|
||||||
extra_ivars(PyTypeObject *type, PyTypeObject *base)
|
extra_ivars(PyTypeObject *type, PyTypeObject *base)
|
||||||
{
|
{
|
||||||
|
@ -2328,10 +2333,18 @@ extra_ivars(PyTypeObject *type, PyTypeObject *base)
|
||||||
return t_size != b_size ||
|
return t_size != b_size ||
|
||||||
type->tp_itemsize != base->tp_itemsize;
|
type->tp_itemsize != base->tp_itemsize;
|
||||||
}
|
}
|
||||||
if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 &&
|
/* Check for __dict__ and __weakrefs__ slots in either order */
|
||||||
type->tp_weaklistoffset + sizeof(PyObject *) == t_size &&
|
if (ADDED_FIELD_AT_OFFSET(weaklistoffset, t_size)) {
|
||||||
type->tp_flags & Py_TPFLAGS_HEAPTYPE)
|
|
||||||
t_size -= sizeof(PyObject *);
|
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;
|
return t_size != b_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue