Skip to content

Commit b5a24b7

Browse files
authored
Fix segfault creating view objects (#1163)
1 parent fea968f commit b5a24b7

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

CHANGES/1164.bugfix.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Fixed a segmentation fault when attempting to directly instantiate view objects
2+
(``multidict._ItemsView``, ``multidict._KeysView``, ``multidict._ValuesView``) -- by :user:`bdraco`.
3+
4+
View objects now raise a proper :exc:`TypeError` with the message "cannot create '...' instances directly"
5+
when direct instantiation is attempted.
6+
7+
View objects should only be created through the proper methods: :py:meth:`multidict.MultiDict.items`,
8+
:py:meth:`multidict.MultiDict.keys`, and :py:meth:`multidict.MultiDict.values`.

multidict/_multilib/views.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,16 @@ static PyMethodDef multidict_itemsview_methods[] = {
10061006
{NULL, NULL} /* sentinel */
10071007
};
10081008

1009+
static inline PyObject *
1010+
multidict_view_forbidden_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
1011+
{
1012+
PyErr_Format(PyExc_TypeError,
1013+
"cannot create '%s' instances directly", type->tp_name);
1014+
return NULL;
1015+
}
1016+
10091017
static PyType_Slot multidict_itemsview_slots[] = {
1018+
{Py_tp_new, multidict_view_forbidden_new},
10101019
{Py_tp_dealloc, multidict_view_dealloc},
10111020
{Py_tp_repr, multidict_itemsview_repr},
10121021

@@ -1561,6 +1570,7 @@ static PyMethodDef multidict_keysview_methods[] = {
15611570
};
15621571

15631572
static PyType_Slot multidict_keysview_slots[] = {
1573+
{Py_tp_new, multidict_view_forbidden_new},
15641574
{Py_tp_dealloc, multidict_view_dealloc},
15651575
{Py_tp_repr, multidict_keysview_repr},
15661576

@@ -1635,6 +1645,7 @@ multidict_valuesview_repr(_Multidict_ViewObject *self)
16351645
}
16361646

16371647
static PyType_Slot multidict_valuesview_slots[] = {
1648+
{Py_tp_new, multidict_view_forbidden_new},
16381649
{Py_tp_dealloc, multidict_view_dealloc},
16391650
{Py_tp_repr, multidict_valuesview_repr},
16401651

tests/test_multidict.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,3 +1324,22 @@ class SubclassedMultiDict(any_multidict_class): # type: ignore[valid-type, misc
13241324
assert d1 == d3
13251325
assert d1 == SubclassedMultiDict([("key", "value1")])
13261326
assert d1 != SubclassedMultiDict([("key", "value2")])
1327+
1328+
1329+
@pytest.mark.c_extension
1330+
def test_view_direct_instantiation_segfault() -> None:
1331+
"""Test that view objects cannot be instantiated directly (issue: segfault).
1332+
1333+
This test only applies to the C extension implementation.
1334+
"""
1335+
# Test that _ItemsView cannot be instantiated directly
1336+
with pytest.raises(TypeError, match="cannot create '.*_ItemsView' instances directly"):
1337+
multidict._ItemsView() # type: ignore[attr-defined]
1338+
1339+
# Test that _KeysView cannot be instantiated directly
1340+
with pytest.raises(TypeError, match="cannot create '.*_KeysView' instances directly"):
1341+
multidict._KeysView() # type: ignore[attr-defined]
1342+
1343+
# Test that _ValuesView cannot be instantiated directly
1344+
with pytest.raises(TypeError, match="cannot create '.*_ValuesView' instances directly"):
1345+
multidict._ValuesView() # type: ignore[attr-defined]

0 commit comments

Comments
 (0)