gh-111178: Avoid calling functions from incompatible pointer types in dictobject.c (#112892)

Fix undefined behavior warnings (UBSan  -fsanitize=function).
This commit is contained in:
Christopher Chavez 2024-01-02 08:32:37 -06:00 committed by GitHub
parent acf4cf5ca5
commit a1eea1d032
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -237,7 +237,7 @@ equally good collision statistics, needed less code & used less memory.
static int dictresize(PyInterpreterState *interp, PyDictObject *mp, static int dictresize(PyInterpreterState *interp, PyDictObject *mp,
uint8_t log_newsize, int unicode); uint8_t log_newsize, int unicode);
static PyObject* dict_iter(PyDictObject *dict); static PyObject* dict_iter(PyObject *dict);
#include "clinic/dictobject.c.h" #include "clinic/dictobject.c.h"
@ -792,7 +792,7 @@ static PyDictKeysObject *
clone_combined_dict_keys(PyDictObject *orig) clone_combined_dict_keys(PyDictObject *orig)
{ {
assert(PyDict_Check(orig)); assert(PyDict_Check(orig));
assert(Py_TYPE(orig)->tp_iter == (getiterfunc)dict_iter); assert(Py_TYPE(orig)->tp_iter == dict_iter);
assert(orig->ma_values == NULL); assert(orig->ma_values == NULL);
assert(orig->ma_keys != Py_EMPTY_KEYS); assert(orig->ma_keys != Py_EMPTY_KEYS);
assert(orig->ma_keys->dk_refcnt == 1); assert(orig->ma_keys->dk_refcnt == 1);
@ -2450,8 +2450,9 @@ Fail:
/* Methods */ /* Methods */
static void static void
dict_dealloc(PyDictObject *mp) dict_dealloc(PyObject *self)
{ {
PyDictObject *mp = (PyDictObject *)self;
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
assert(Py_REFCNT(mp) == 0); assert(Py_REFCNT(mp) == 0);
Py_SET_REFCNT(mp, 1); Py_SET_REFCNT(mp, 1);
@ -2499,8 +2500,9 @@ dict_dealloc(PyDictObject *mp)
static PyObject * static PyObject *
dict_repr(PyDictObject *mp) dict_repr(PyObject *self)
{ {
PyDictObject *mp = (PyDictObject *)self;
Py_ssize_t i; Py_ssize_t i;
PyObject *key = NULL, *value = NULL; PyObject *key = NULL, *value = NULL;
_PyUnicodeWriter writer; _PyUnicodeWriter writer;
@ -2582,14 +2584,16 @@ error:
} }
static Py_ssize_t static Py_ssize_t
dict_length(PyDictObject *mp) dict_length(PyObject *self)
{ {
PyDictObject *mp = (PyDictObject *)self;
return mp->ma_used; return mp->ma_used;
} }
static PyObject * static PyObject *
dict_subscript(PyDictObject *mp, PyObject *key) dict_subscript(PyObject *self, PyObject *key)
{ {
PyDictObject *mp = (PyDictObject *)self;
Py_ssize_t ix; Py_ssize_t ix;
Py_hash_t hash; Py_hash_t hash;
PyObject *value; PyObject *value;
@ -2623,18 +2627,18 @@ dict_subscript(PyDictObject *mp, PyObject *key)
} }
static int static int
dict_ass_sub(PyDictObject *mp, PyObject *v, PyObject *w) dict_ass_sub(PyObject *mp, PyObject *v, PyObject *w)
{ {
if (w == NULL) if (w == NULL)
return PyDict_DelItem((PyObject *)mp, v); return PyDict_DelItem(mp, v);
else else
return PyDict_SetItem((PyObject *)mp, v, w); return PyDict_SetItem(mp, v, w);
} }
static PyMappingMethods dict_as_mapping = { static PyMappingMethods dict_as_mapping = {
(lenfunc)dict_length, /*mp_length*/ dict_length, /*mp_length*/
(binaryfunc)dict_subscript, /*mp_subscript*/ dict_subscript, /*mp_subscript*/
(objobjargproc)dict_ass_sub, /*mp_ass_subscript*/ dict_ass_sub, /*mp_ass_subscript*/
}; };
static PyObject * static PyObject *
@ -2925,7 +2929,7 @@ dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override)
return -1; return -1;
} }
mp = (PyDictObject*)a; mp = (PyDictObject*)a;
if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == (getiterfunc)dict_iter)) { if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == dict_iter)) {
other = (PyDictObject*)b; other = (PyDictObject*)b;
if (other == mp || other->ma_used == 0) if (other == mp || other->ma_used == 0)
/* a.update(a) or a.update({}); nothing to do */ /* a.update(a) or a.update({}); nothing to do */
@ -3105,9 +3109,9 @@ _PyDict_MergeEx(PyObject *a, PyObject *b, int override)
} }
static PyObject * static PyObject *
dict_copy(PyDictObject *mp, PyObject *Py_UNUSED(ignored)) dict_copy(PyObject *mp, PyObject *Py_UNUSED(ignored))
{ {
return PyDict_Copy((PyObject*)mp); return PyDict_Copy(mp);
} }
PyObject * PyObject *
@ -3155,7 +3159,7 @@ PyDict_Copy(PyObject *o)
return (PyObject *)split_copy; return (PyObject *)split_copy;
} }
if (Py_TYPE(mp)->tp_iter == (getiterfunc)dict_iter && if (Py_TYPE(mp)->tp_iter == dict_iter &&
mp->ma_values == NULL && mp->ma_values == NULL &&
(mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3)) (mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3))
{ {
@ -3509,9 +3513,9 @@ dict_setdefault_impl(PyDictObject *self, PyObject *key,
} }
static PyObject * static PyObject *
dict_clear(PyDictObject *mp, PyObject *Py_UNUSED(ignored)) dict_clear(PyObject *mp, PyObject *Py_UNUSED(ignored))
{ {
PyDict_Clear((PyObject *)mp); PyDict_Clear(mp);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -3700,8 +3704,9 @@ _PyDict_KeysSize(PyDictKeysObject *keys)
} }
static PyObject * static PyObject *
dict_sizeof(PyDictObject *mp, PyObject *Py_UNUSED(ignored)) dict_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
PyDictObject *mp = (PyDictObject *)self;
return PyLong_FromSsize_t(_PyDict_SizeOf(mp)); return PyLong_FromSsize_t(_PyDict_SizeOf(mp));
} }
@ -3763,9 +3768,9 @@ PyDoc_STRVAR(values__doc__,
static PyMethodDef mapp_methods[] = { static PyMethodDef mapp_methods[] = {
DICT___CONTAINS___METHODDEF DICT___CONTAINS___METHODDEF
{"__getitem__", _PyCFunction_CAST(dict_subscript), METH_O | METH_COEXIST, {"__getitem__", dict_subscript, METH_O | METH_COEXIST,
getitem__doc__}, getitem__doc__},
{"__sizeof__", _PyCFunction_CAST(dict_sizeof), METH_NOARGS, {"__sizeof__", dict_sizeof, METH_NOARGS,
sizeof__doc__}, sizeof__doc__},
DICT_GET_METHODDEF DICT_GET_METHODDEF
DICT_SETDEFAULT_METHODDEF DICT_SETDEFAULT_METHODDEF
@ -3780,9 +3785,9 @@ static PyMethodDef mapp_methods[] = {
{"update", _PyCFunction_CAST(dict_update), METH_VARARGS | METH_KEYWORDS, {"update", _PyCFunction_CAST(dict_update), METH_VARARGS | METH_KEYWORDS,
update__doc__}, update__doc__},
DICT_FROMKEYS_METHODDEF DICT_FROMKEYS_METHODDEF
{"clear", (PyCFunction)dict_clear, METH_NOARGS, {"clear", dict_clear, METH_NOARGS,
clear__doc__}, clear__doc__},
{"copy", (PyCFunction)dict_copy, METH_NOARGS, {"copy", dict_copy, METH_NOARGS,
copy__doc__}, copy__doc__},
DICT___REVERSED___METHODDEF DICT___REVERSED___METHODDEF
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
@ -3937,8 +3942,9 @@ dict_vectorcall(PyObject *type, PyObject * const*args,
} }
static PyObject * static PyObject *
dict_iter(PyDictObject *dict) dict_iter(PyObject *self)
{ {
PyDictObject *dict = (PyDictObject *)self;
return dictiter_new(dict, &PyDictIterKey_Type); return dictiter_new(dict, &PyDictIterKey_Type);
} }
@ -3958,12 +3964,12 @@ PyTypeObject PyDict_Type = {
"dict", "dict",
sizeof(PyDictObject), sizeof(PyDictObject),
0, 0,
(destructor)dict_dealloc, /* tp_dealloc */ dict_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */ 0, /* tp_vectorcall_offset */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_as_async */ 0, /* tp_as_async */
(reprfunc)dict_repr, /* tp_repr */ dict_repr, /* tp_repr */
&dict_as_number, /* tp_as_number */ &dict_as_number, /* tp_as_number */
&dict_as_sequence, /* tp_as_sequence */ &dict_as_sequence, /* tp_as_sequence */
&dict_as_mapping, /* tp_as_mapping */ &dict_as_mapping, /* tp_as_mapping */
@ -3981,7 +3987,7 @@ PyTypeObject PyDict_Type = {
dict_tp_clear, /* tp_clear */ dict_tp_clear, /* tp_clear */
dict_richcompare, /* tp_richcompare */ dict_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
(getiterfunc)dict_iter, /* tp_iter */ dict_iter, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
mapp_methods, /* tp_methods */ mapp_methods, /* tp_methods */
0, /* tp_members */ 0, /* tp_members */
@ -4128,8 +4134,9 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
} }
static void static void
dictiter_dealloc(dictiterobject *di) dictiter_dealloc(PyObject *self)
{ {
dictiterobject *di = (dictiterobject *)self;
/* bpo-31095: UnTrack is needed before calling any callbacks */ /* bpo-31095: UnTrack is needed before calling any callbacks */
_PyObject_GC_UNTRACK(di); _PyObject_GC_UNTRACK(di);
Py_XDECREF(di->di_dict); Py_XDECREF(di->di_dict);
@ -4138,16 +4145,18 @@ dictiter_dealloc(dictiterobject *di)
} }
static int static int
dictiter_traverse(dictiterobject *di, visitproc visit, void *arg) dictiter_traverse(PyObject *self, visitproc visit, void *arg)
{ {
dictiterobject *di = (dictiterobject *)self;
Py_VISIT(di->di_dict); Py_VISIT(di->di_dict);
Py_VISIT(di->di_result); Py_VISIT(di->di_result);
return 0; return 0;
} }
static PyObject * static PyObject *
dictiter_len(dictiterobject *di, PyObject *Py_UNUSED(ignored)) dictiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
dictiterobject *di = (dictiterobject *)self;
Py_ssize_t len = 0; Py_ssize_t len = 0;
if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used) if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used)
len = di->len; len = di->len;
@ -4158,21 +4167,22 @@ PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it))."); "Private method returning an estimate of len(list(it)).");
static PyObject * static PyObject *
dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored)); dictiter_reduce(PyObject *di, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
static PyMethodDef dictiter_methods[] = { static PyMethodDef dictiter_methods[] = {
{"__length_hint__", _PyCFunction_CAST(dictiter_len), METH_NOARGS, {"__length_hint__", dictiter_len, METH_NOARGS,
length_hint_doc}, length_hint_doc},
{"__reduce__", _PyCFunction_CAST(dictiter_reduce), METH_NOARGS, {"__reduce__", dictiter_reduce, METH_NOARGS,
reduce_doc}, reduce_doc},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
static PyObject* static PyObject*
dictiter_iternextkey(dictiterobject *di) dictiter_iternextkey(PyObject *self)
{ {
dictiterobject *di = (dictiterobject *)self;
PyObject *key; PyObject *key;
Py_ssize_t i; Py_ssize_t i;
PyDictKeysObject *k; PyDictKeysObject *k;
@ -4244,7 +4254,7 @@ PyTypeObject PyDictIterKey_Type = {
sizeof(dictiterobject), /* tp_basicsize */ sizeof(dictiterobject), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* methods */ /* methods */
(destructor)dictiter_dealloc, /* tp_dealloc */ dictiter_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */ 0, /* tp_vectorcall_offset */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
@ -4261,19 +4271,20 @@ PyTypeObject PyDictIterKey_Type = {
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)dictiter_traverse, /* tp_traverse */ dictiter_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */ PyObject_SelfIter, /* tp_iter */
(iternextfunc)dictiter_iternextkey, /* tp_iternext */ dictiter_iternextkey, /* tp_iternext */
dictiter_methods, /* tp_methods */ dictiter_methods, /* tp_methods */
0, 0,
}; };
static PyObject * static PyObject *
dictiter_iternextvalue(dictiterobject *di) dictiter_iternextvalue(PyObject *self)
{ {
dictiterobject *di = (dictiterobject *)self;
PyObject *value; PyObject *value;
Py_ssize_t i; Py_ssize_t i;
PyDictObject *d = di->di_dict; PyDictObject *d = di->di_dict;
@ -4343,7 +4354,7 @@ PyTypeObject PyDictIterValue_Type = {
sizeof(dictiterobject), /* tp_basicsize */ sizeof(dictiterobject), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* methods */ /* methods */
(destructor)dictiter_dealloc, /* tp_dealloc */ dictiter_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */ 0, /* tp_vectorcall_offset */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
@ -4360,19 +4371,20 @@ PyTypeObject PyDictIterValue_Type = {
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)dictiter_traverse, /* tp_traverse */ dictiter_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */ PyObject_SelfIter, /* tp_iter */
(iternextfunc)dictiter_iternextvalue, /* tp_iternext */ dictiter_iternextvalue, /* tp_iternext */
dictiter_methods, /* tp_methods */ dictiter_methods, /* tp_methods */
0, 0,
}; };
static PyObject * static PyObject *
dictiter_iternextitem(dictiterobject *di) dictiter_iternextitem(PyObject *self)
{ {
dictiterobject *di = (dictiterobject *)self;
PyObject *key, *value, *result; PyObject *key, *value, *result;
Py_ssize_t i; Py_ssize_t i;
PyDictObject *d = di->di_dict; PyDictObject *d = di->di_dict;
@ -4467,7 +4479,7 @@ PyTypeObject PyDictIterItem_Type = {
sizeof(dictiterobject), /* tp_basicsize */ sizeof(dictiterobject), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* methods */ /* methods */
(destructor)dictiter_dealloc, /* tp_dealloc */ dictiter_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */ 0, /* tp_vectorcall_offset */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
@ -4484,12 +4496,12 @@ PyTypeObject PyDictIterItem_Type = {
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)dictiter_traverse, /* tp_traverse */ dictiter_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */ PyObject_SelfIter, /* tp_iter */
(iternextfunc)dictiter_iternextitem, /* tp_iternext */ dictiter_iternextitem, /* tp_iternext */
dictiter_methods, /* tp_methods */ dictiter_methods, /* tp_methods */
0, 0,
}; };
@ -4498,8 +4510,9 @@ PyTypeObject PyDictIterItem_Type = {
/* dictreviter */ /* dictreviter */
static PyObject * static PyObject *
dictreviter_iternext(dictiterobject *di) dictreviter_iternext(PyObject *self)
{ {
dictiterobject *di = (dictiterobject *)self;
PyDictObject *d = di->di_dict; PyDictObject *d = di->di_dict;
if (d == NULL) { if (d == NULL) {
@ -4600,11 +4613,11 @@ PyTypeObject PyDictRevIterKey_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"dict_reversekeyiterator", "dict_reversekeyiterator",
sizeof(dictiterobject), sizeof(dictiterobject),
.tp_dealloc = (destructor)dictiter_dealloc, .tp_dealloc = dictiter_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
.tp_traverse = (traverseproc)dictiter_traverse, .tp_traverse = dictiter_traverse,
.tp_iter = PyObject_SelfIter, .tp_iter = PyObject_SelfIter,
.tp_iternext = (iternextfunc)dictreviter_iternext, .tp_iternext = dictreviter_iternext,
.tp_methods = dictiter_methods .tp_methods = dictiter_methods
}; };
@ -4624,8 +4637,9 @@ dict___reversed___impl(PyDictObject *self)
} }
static PyObject * static PyObject *
dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored)) dictiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
dictiterobject *di = (dictiterobject *)self;
/* copy the iterator state */ /* copy the iterator state */
dictiterobject tmp = *di; dictiterobject tmp = *di;
Py_XINCREF(tmp.di_dict); Py_XINCREF(tmp.di_dict);
@ -4641,11 +4655,11 @@ PyTypeObject PyDictRevIterItem_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"dict_reverseitemiterator", "dict_reverseitemiterator",
sizeof(dictiterobject), sizeof(dictiterobject),
.tp_dealloc = (destructor)dictiter_dealloc, .tp_dealloc = dictiter_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
.tp_traverse = (traverseproc)dictiter_traverse, .tp_traverse = dictiter_traverse,
.tp_iter = PyObject_SelfIter, .tp_iter = PyObject_SelfIter,
.tp_iternext = (iternextfunc)dictreviter_iternext, .tp_iternext = dictreviter_iternext,
.tp_methods = dictiter_methods .tp_methods = dictiter_methods
}; };
@ -4653,11 +4667,11 @@ PyTypeObject PyDictRevIterValue_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"dict_reversevalueiterator", "dict_reversevalueiterator",
sizeof(dictiterobject), sizeof(dictiterobject),
.tp_dealloc = (destructor)dictiter_dealloc, .tp_dealloc = dictiter_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
.tp_traverse = (traverseproc)dictiter_traverse, .tp_traverse = dictiter_traverse,
.tp_iter = PyObject_SelfIter, .tp_iter = PyObject_SelfIter,
.tp_iternext = (iternextfunc)dictreviter_iternext, .tp_iternext = dictreviter_iternext,
.tp_methods = dictiter_methods .tp_methods = dictiter_methods
}; };
@ -4668,8 +4682,9 @@ PyTypeObject PyDictRevIterValue_Type = {
/* The instance lay-out is the same for all three; but the type differs. */ /* The instance lay-out is the same for all three; but the type differs. */
static void static void
dictview_dealloc(_PyDictViewObject *dv) dictview_dealloc(PyObject *self)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
/* bpo-31095: UnTrack is needed before calling any callbacks */ /* bpo-31095: UnTrack is needed before calling any callbacks */
_PyObject_GC_UNTRACK(dv); _PyObject_GC_UNTRACK(dv);
Py_XDECREF(dv->dv_dict); Py_XDECREF(dv->dv_dict);
@ -4677,15 +4692,17 @@ dictview_dealloc(_PyDictViewObject *dv)
} }
static int static int
dictview_traverse(_PyDictViewObject *dv, visitproc visit, void *arg) dictview_traverse(PyObject *self, visitproc visit, void *arg)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
Py_VISIT(dv->dv_dict); Py_VISIT(dv->dv_dict);
return 0; return 0;
} }
static Py_ssize_t static Py_ssize_t
dictview_len(_PyDictViewObject *dv) dictview_len(PyObject *self)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
Py_ssize_t len = 0; Py_ssize_t len = 0;
if (dv->dv_dict != NULL) if (dv->dv_dict != NULL)
len = dv->dv_dict->ma_used; len = dv->dv_dict->ma_used;
@ -4825,8 +4842,9 @@ dictview_richcompare(PyObject *self, PyObject *other, int op)
} }
static PyObject * static PyObject *
dictview_repr(_PyDictViewObject *dv) dictview_repr(PyObject *self)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
PyObject *seq; PyObject *seq;
PyObject *result = NULL; PyObject *result = NULL;
Py_ssize_t rc; Py_ssize_t rc;
@ -4850,8 +4868,9 @@ Done:
/*** dict_keys ***/ /*** dict_keys ***/
static PyObject * static PyObject *
dictkeys_iter(_PyDictViewObject *dv) dictkeys_iter(PyObject *self)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
if (dv->dv_dict == NULL) { if (dv->dv_dict == NULL) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -4859,22 +4878,23 @@ dictkeys_iter(_PyDictViewObject *dv)
} }
static int static int
dictkeys_contains(_PyDictViewObject *dv, PyObject *obj) dictkeys_contains(PyObject *self, PyObject *obj)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
if (dv->dv_dict == NULL) if (dv->dv_dict == NULL)
return 0; return 0;
return PyDict_Contains((PyObject *)dv->dv_dict, obj); return PyDict_Contains((PyObject *)dv->dv_dict, obj);
} }
static PySequenceMethods dictkeys_as_sequence = { static PySequenceMethods dictkeys_as_sequence = {
(lenfunc)dictview_len, /* sq_length */ dictview_len, /* sq_length */
0, /* sq_concat */ 0, /* sq_concat */
0, /* sq_repeat */ 0, /* sq_repeat */
0, /* sq_item */ 0, /* sq_item */
0, /* sq_slice */ 0, /* sq_slice */
0, /* sq_ass_item */ 0, /* sq_ass_item */
0, /* sq_ass_slice */ 0, /* sq_ass_slice */
(objobjproc)dictkeys_contains, /* sq_contains */ dictkeys_contains, /* sq_contains */
}; };
// Create a set object from dictviews object. // Create a set object from dictviews object.
@ -4914,7 +4934,7 @@ dictviews_sub(PyObject *self, PyObject *other)
} }
static int static int
dictitems_contains(_PyDictViewObject *dv, PyObject *obj); dictitems_contains(PyObject *dv, PyObject *obj);
PyObject * PyObject *
_PyDictView_Intersect(PyObject* self, PyObject *other) _PyDictView_Intersect(PyObject* self, PyObject *other)
@ -4924,7 +4944,7 @@ _PyDictView_Intersect(PyObject* self, PyObject *other)
PyObject *key; PyObject *key;
Py_ssize_t len_self; Py_ssize_t len_self;
int rv; int rv;
int (*dict_contains)(_PyDictViewObject *, PyObject *); objobjproc dict_contains;
/* Python interpreter swaps parameters when dict view /* Python interpreter swaps parameters when dict view
is on right side of & */ is on right side of & */
@ -4934,7 +4954,7 @@ _PyDictView_Intersect(PyObject* self, PyObject *other)
self = tmp; self = tmp;
} }
len_self = dictview_len((_PyDictViewObject *)self); len_self = dictview_len(self);
/* if other is a set and self is smaller than other, /* if other is a set and self is smaller than other,
reuse set intersection logic */ reuse set intersection logic */
@ -4946,7 +4966,7 @@ _PyDictView_Intersect(PyObject* self, PyObject *other)
/* if other is another dict view, and it is bigger than self, /* if other is another dict view, and it is bigger than self,
swap them */ swap them */
if (PyDictViewSet_Check(other)) { if (PyDictViewSet_Check(other)) {
Py_ssize_t len_other = dictview_len((_PyDictViewObject *)other); Py_ssize_t len_other = dictview_len(other);
if (len_other > len_self) { if (len_other > len_self) {
PyObject *tmp = other; PyObject *tmp = other;
other = self; other = self;
@ -4976,7 +4996,7 @@ _PyDictView_Intersect(PyObject* self, PyObject *other)
} }
while ((key = PyIter_Next(it)) != NULL) { while ((key = PyIter_Next(it)) != NULL) {
rv = dict_contains((_PyDictViewObject *)self, key); rv = dict_contains(self, key);
if (rv < 0) { if (rv < 0) {
goto error; goto error;
} }
@ -5150,7 +5170,7 @@ dictviews_isdisjoint(PyObject *self, PyObject *other)
PyObject *item = NULL; PyObject *item = NULL;
if (self == other) { if (self == other) {
if (dictview_len((_PyDictViewObject *)self) == 0) if (dictview_len(self) == 0)
Py_RETURN_TRUE; Py_RETURN_TRUE;
else else
Py_RETURN_FALSE; Py_RETURN_FALSE;
@ -5159,7 +5179,7 @@ dictviews_isdisjoint(PyObject *self, PyObject *other)
/* Iterate over the shorter object (only if other is a set, /* Iterate over the shorter object (only if other is a set,
* because PySequence_Contains may be expensive otherwise): */ * because PySequence_Contains may be expensive otherwise): */
if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) { if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) {
Py_ssize_t len_self = dictview_len((_PyDictViewObject *)self); Py_ssize_t len_self = dictview_len(self);
Py_ssize_t len_other = PyObject_Size(other); Py_ssize_t len_other = PyObject_Size(other);
if (len_other == -1) if (len_other == -1)
return NULL; return NULL;
@ -5197,15 +5217,15 @@ dictviews_isdisjoint(PyObject *self, PyObject *other)
PyDoc_STRVAR(isdisjoint_doc, PyDoc_STRVAR(isdisjoint_doc,
"Return True if the view and the given iterable have a null intersection."); "Return True if the view and the given iterable have a null intersection.");
static PyObject* dictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored)); static PyObject* dictkeys_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_keys_doc, PyDoc_STRVAR(reversed_keys_doc,
"Return a reverse iterator over the dict keys."); "Return a reverse iterator over the dict keys.");
static PyMethodDef dictkeys_methods[] = { static PyMethodDef dictkeys_methods[] = {
{"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O, {"isdisjoint", dictviews_isdisjoint, METH_O,
isdisjoint_doc}, isdisjoint_doc},
{"__reversed__", _PyCFunction_CAST(dictkeys_reversed), METH_NOARGS, {"__reversed__", dictkeys_reversed, METH_NOARGS,
reversed_keys_doc}, reversed_keys_doc},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
@ -5216,12 +5236,12 @@ PyTypeObject PyDictKeys_Type = {
sizeof(_PyDictViewObject), /* tp_basicsize */ sizeof(_PyDictViewObject), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* methods */ /* methods */
(destructor)dictview_dealloc, /* tp_dealloc */ dictview_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */ 0, /* tp_vectorcall_offset */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_as_async */ 0, /* tp_as_async */
(reprfunc)dictview_repr, /* tp_repr */ dictview_repr, /* tp_repr */
&dictviews_as_number, /* tp_as_number */ &dictviews_as_number, /* tp_as_number */
&dictkeys_as_sequence, /* tp_as_sequence */ &dictkeys_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */ 0, /* tp_as_mapping */
@ -5233,11 +5253,11 @@ PyTypeObject PyDictKeys_Type = {
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)dictview_traverse, /* tp_traverse */ dictview_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
dictview_richcompare, /* tp_richcompare */ dictview_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
(getiterfunc)dictkeys_iter, /* tp_iter */ dictkeys_iter, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
dictkeys_methods, /* tp_methods */ dictkeys_methods, /* tp_methods */
.tp_getset = dictview_getset, .tp_getset = dictview_getset,
@ -5250,8 +5270,9 @@ dictkeys_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
} }
static PyObject * static PyObject *
dictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored)) dictkeys_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
if (dv->dv_dict == NULL) { if (dv->dv_dict == NULL) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -5261,8 +5282,9 @@ dictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
/*** dict_items ***/ /*** dict_items ***/
static PyObject * static PyObject *
dictitems_iter(_PyDictViewObject *dv) dictitems_iter(PyObject *self)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
if (dv->dv_dict == NULL) { if (dv->dv_dict == NULL) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -5270,8 +5292,9 @@ dictitems_iter(_PyDictViewObject *dv)
} }
static int static int
dictitems_contains(_PyDictViewObject *dv, PyObject *obj) dictitems_contains(PyObject *self, PyObject *obj)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
int result; int result;
PyObject *key, *value, *found; PyObject *key, *value, *found;
if (dv->dv_dict == NULL) if (dv->dv_dict == NULL)
@ -5289,25 +5312,25 @@ dictitems_contains(_PyDictViewObject *dv, PyObject *obj)
} }
static PySequenceMethods dictitems_as_sequence = { static PySequenceMethods dictitems_as_sequence = {
(lenfunc)dictview_len, /* sq_length */ dictview_len, /* sq_length */
0, /* sq_concat */ 0, /* sq_concat */
0, /* sq_repeat */ 0, /* sq_repeat */
0, /* sq_item */ 0, /* sq_item */
0, /* sq_slice */ 0, /* sq_slice */
0, /* sq_ass_item */ 0, /* sq_ass_item */
0, /* sq_ass_slice */ 0, /* sq_ass_slice */
(objobjproc)dictitems_contains, /* sq_contains */ dictitems_contains, /* sq_contains */
}; };
static PyObject* dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored)); static PyObject* dictitems_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_items_doc, PyDoc_STRVAR(reversed_items_doc,
"Return a reverse iterator over the dict items."); "Return a reverse iterator over the dict items.");
static PyMethodDef dictitems_methods[] = { static PyMethodDef dictitems_methods[] = {
{"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O, {"isdisjoint", dictviews_isdisjoint, METH_O,
isdisjoint_doc}, isdisjoint_doc},
{"__reversed__", (PyCFunction)dictitems_reversed, METH_NOARGS, {"__reversed__", dictitems_reversed, METH_NOARGS,
reversed_items_doc}, reversed_items_doc},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
@ -5318,12 +5341,12 @@ PyTypeObject PyDictItems_Type = {
sizeof(_PyDictViewObject), /* tp_basicsize */ sizeof(_PyDictViewObject), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* methods */ /* methods */
(destructor)dictview_dealloc, /* tp_dealloc */ dictview_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */ 0, /* tp_vectorcall_offset */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_as_async */ 0, /* tp_as_async */
(reprfunc)dictview_repr, /* tp_repr */ dictview_repr, /* tp_repr */
&dictviews_as_number, /* tp_as_number */ &dictviews_as_number, /* tp_as_number */
&dictitems_as_sequence, /* tp_as_sequence */ &dictitems_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */ 0, /* tp_as_mapping */
@ -5335,11 +5358,11 @@ PyTypeObject PyDictItems_Type = {
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)dictview_traverse, /* tp_traverse */ dictview_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
dictview_richcompare, /* tp_richcompare */ dictview_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
(getiterfunc)dictitems_iter, /* tp_iter */ dictitems_iter, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
dictitems_methods, /* tp_methods */ dictitems_methods, /* tp_methods */
.tp_getset = dictview_getset, .tp_getset = dictview_getset,
@ -5352,8 +5375,9 @@ dictitems_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
} }
static PyObject * static PyObject *
dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored)) dictitems_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
if (dv->dv_dict == NULL) { if (dv->dv_dict == NULL) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -5363,8 +5387,9 @@ dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
/*** dict_values ***/ /*** dict_values ***/
static PyObject * static PyObject *
dictvalues_iter(_PyDictViewObject *dv) dictvalues_iter(PyObject *self)
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
if (dv->dv_dict == NULL) { if (dv->dv_dict == NULL) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -5372,7 +5397,7 @@ dictvalues_iter(_PyDictViewObject *dv)
} }
static PySequenceMethods dictvalues_as_sequence = { static PySequenceMethods dictvalues_as_sequence = {
(lenfunc)dictview_len, /* sq_length */ dictview_len, /* sq_length */
0, /* sq_concat */ 0, /* sq_concat */
0, /* sq_repeat */ 0, /* sq_repeat */
0, /* sq_item */ 0, /* sq_item */
@ -5382,13 +5407,13 @@ static PySequenceMethods dictvalues_as_sequence = {
(objobjproc)0, /* sq_contains */ (objobjproc)0, /* sq_contains */
}; };
static PyObject* dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored)); static PyObject* dictvalues_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_values_doc, PyDoc_STRVAR(reversed_values_doc,
"Return a reverse iterator over the dict values."); "Return a reverse iterator over the dict values.");
static PyMethodDef dictvalues_methods[] = { static PyMethodDef dictvalues_methods[] = {
{"__reversed__", (PyCFunction)dictvalues_reversed, METH_NOARGS, {"__reversed__", dictvalues_reversed, METH_NOARGS,
reversed_values_doc}, reversed_values_doc},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
@ -5399,12 +5424,12 @@ PyTypeObject PyDictValues_Type = {
sizeof(_PyDictViewObject), /* tp_basicsize */ sizeof(_PyDictViewObject), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* methods */ /* methods */
(destructor)dictview_dealloc, /* tp_dealloc */ dictview_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */ 0, /* tp_vectorcall_offset */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_as_async */ 0, /* tp_as_async */
(reprfunc)dictview_repr, /* tp_repr */ dictview_repr, /* tp_repr */
0, /* tp_as_number */ 0, /* tp_as_number */
&dictvalues_as_sequence, /* tp_as_sequence */ &dictvalues_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */ 0, /* tp_as_mapping */
@ -5416,11 +5441,11 @@ PyTypeObject PyDictValues_Type = {
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)dictview_traverse, /* tp_traverse */ dictview_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
(getiterfunc)dictvalues_iter, /* tp_iter */ dictvalues_iter, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
dictvalues_methods, /* tp_methods */ dictvalues_methods, /* tp_methods */
.tp_getset = dictview_getset, .tp_getset = dictview_getset,
@ -5433,8 +5458,9 @@ dictvalues_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
} }
static PyObject * static PyObject *
dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored)) dictvalues_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
_PyDictViewObject *dv = (_PyDictViewObject *)self;
if (dv->dv_dict == NULL) { if (dv->dv_dict == NULL) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }