summaryrefslogtreecommitdiffstats
path: root/Objects/structseq.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/structseq.c')
-rw-r--r--Objects/structseq.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/Objects/structseq.c b/Objects/structseq.c
index d8289f2..94f09b3 100644
--- a/Objects/structseq.c
+++ b/Objects/structseq.c
@@ -41,12 +41,20 @@ get_type_attr_as_size(PyTypeObject *tp, PyObject *name)
get_type_attr_as_size(tp, &_Py_ID(n_sequence_fields))
#define REAL_SIZE_TP(tp) \
get_type_attr_as_size(tp, &_Py_ID(n_fields))
-#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
+#define REAL_SIZE(op) get_real_size((PyObject *)op)
#define UNNAMED_FIELDS_TP(tp) \
get_type_attr_as_size(tp, &_Py_ID(n_unnamed_fields))
#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
+static Py_ssize_t
+get_real_size(PyObject *op)
+{
+ // Compute the real size from the visible size (i.e., Py_SIZE()) and the
+ // number of non-sequence fields accounted for in tp_basicsize.
+ Py_ssize_t hidden = Py_TYPE(op)->tp_basicsize - offsetof(PyStructSequence, ob_item);
+ return Py_SIZE(op) + hidden / sizeof(PyObject *);
+}
PyObject *
PyStructSequence_New(PyTypeObject *type)
@@ -120,6 +128,9 @@ structseq_dealloc(PyStructSequence *obj)
PyObject_GC_UnTrack(obj);
PyTypeObject *tp = Py_TYPE(obj);
+ // gh-122527: We can't use REAL_SIZE_TP() or any macros that access the
+ // type's dictionary here, because the dictionary may have already been
+ // cleared by the garbage collector.
size = REAL_SIZE(obj);
for (i = 0; i < size; ++i) {
Py_XDECREF(obj->ob_item[i]);
@@ -565,10 +576,14 @@ initialize_members(PyStructSequence_Desc *desc,
static void
initialize_static_fields(PyTypeObject *type, PyStructSequence_Desc *desc,
- PyMemberDef *tp_members, unsigned long tp_flags)
+ PyMemberDef *tp_members, Py_ssize_t n_members,
+ unsigned long tp_flags)
{
type->tp_name = desc->name;
- type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
+ // Account for hidden members in tp_basicsize because they are not
+ // included in the variable size.
+ Py_ssize_t n_hidden = n_members - desc->n_in_sequence;
+ type->tp_basicsize = sizeof(PyStructSequence) + (n_hidden - 1) * sizeof(PyObject *);
type->tp_itemsize = sizeof(PyObject *);
type->tp_dealloc = (destructor)structseq_dealloc;
type->tp_repr = (reprfunc)structseq_repr;
@@ -621,7 +636,7 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
if (members == NULL) {
goto error;
}
- initialize_static_fields(type, desc, members, tp_flags);
+ initialize_static_fields(type, desc, members, n_members, tp_flags);
_Py_SetImmortal((PyObject *)type);
}
@@ -684,7 +699,7 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
if (members == NULL) {
return -1;
}
- initialize_static_fields(type, desc, members, 0);
+ initialize_static_fields(type, desc, members, n_members, 0);
if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
PyMem_Free(members);
return -1;
@@ -760,7 +775,8 @@ _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags)
/* The name in this PyType_Spec is statically allocated so it is */
/* expected that it'll outlive the PyType_Spec */
spec.name = desc->name;
- spec.basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
+ Py_ssize_t hidden = n_members - desc->n_in_sequence;
+ spec.basicsize = (int)(sizeof(PyStructSequence) + (hidden - 1) * sizeof(PyObject *));
spec.itemsize = sizeof(PyObject *);
spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
spec.slots = slots;