Skip to content

Commit c7d3d1d

Browse files
authored
Merge branch 'master' into iterator-ref-leak
2 parents 959a16b + edb61e8 commit c7d3d1d

File tree

5 files changed

+58
-6
lines changed

5 files changed

+58
-6
lines changed

CHANGES/1310.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
A segmentation fault that could be triggered when getting an item is now fixed
2+
-- by :user:`Vizonex`.

multidict/_multidict_py.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,8 +834,22 @@ def _parse_args(
834834
f"multidict update sequence element #{pos} "
835835
f"has length {len(item)}; 2 is required"
836836
)
837-
identity = identity_func(item[0])
838-
yield _Entry(hash(identity), identity, item[0], item[1])
837+
try:
838+
key = item[0]
839+
except Exception as exc:
840+
raise ValueError(
841+
f"multidict update sequence element #{pos}'s "
842+
f"key could not be fetched"
843+
) from exc
844+
try:
845+
value = item[1]
846+
except Exception as exc:
847+
raise ValueError(
848+
f"multidict update sequence element #{pos}'s "
849+
f"value could not be fetched"
850+
) from exc
851+
identity = identity_func(key)
852+
yield _Entry(hash(identity), identity, key, value)
839853
else:
840854
yield len(kwargs)
841855
for key, value in kwargs.items():

multidict/_multilib/hashtable.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,8 +1470,8 @@ _err_cannot_fetch(Py_ssize_t i, const char *name)
14701470
PyErr_Format(PyExc_ValueError,
14711471
"multidict update sequence element #%zd's "
14721472
"%s could not be fetched",
1473-
name,
1474-
i);
1473+
i,
1474+
name);
14751475
}
14761476

14771477
static int
@@ -1507,11 +1507,11 @@ _md_parse_item(Py_ssize_t i, PyObject *item, PyObject **pkey,
15071507
goto fail;
15081508
}
15091509
*pkey = PySequence_ITEM(item, 0);
1510-
*pvalue = PySequence_ITEM(item, 1);
15111510
if (*pkey == NULL) {
15121511
_err_cannot_fetch(i, "key");
15131512
goto fail;
15141513
}
1514+
*pvalue = PySequence_ITEM(item, 1);
15151515
if (*pvalue == NULL) {
15161516
_err_cannot_fetch(i, "value");
15171517
goto fail;

requirements/pytest.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cffi<2.0.0;python_version<"3.14"
22
objgraph==3.6.2
33
pytest==8.4.2
4-
pytest-codspeed==4.3.0
4+
pytest-codspeed==4.4.0
55
pytest-cov==7.1.0
66
psutil==7.2.2

tests/test_multidict.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,42 @@ def test_cannot_create_from_unaccepted(
300300
):
301301
cls([(1, 2, 3)]) # type: ignore[call-arg]
302302

303+
def test_cannot_create_from_item_with_failing_getitem(
304+
self,
305+
cls: type[MutableMultiMapping[str]],
306+
) -> None:
307+
class BadItem:
308+
def __len__(self) -> int:
309+
return 2
310+
311+
def __getitem__(self, i: int) -> object:
312+
raise RuntimeError("intentional getitem failure")
313+
314+
with pytest.raises(
315+
ValueError,
316+
match=r"^multidict update sequence element #0's key could not be fetched$",
317+
):
318+
cls([BadItem()]) # type: ignore[call-arg]
319+
320+
def test_cannot_create_from_item_with_failing_getitem_value(
321+
self,
322+
cls: type[MutableMultiMapping[str]],
323+
) -> None:
324+
class BadValueItem:
325+
def __len__(self) -> int:
326+
return 2
327+
328+
def __getitem__(self, i: int) -> object:
329+
if i == 0:
330+
return "key"
331+
raise RuntimeError("intentional getitem failure")
332+
333+
with pytest.raises(
334+
ValueError,
335+
match=r"^multidict update sequence element #0's value could not be fetched$",
336+
):
337+
cls([BadValueItem()]) # type: ignore[call-arg]
338+
303339
def test_keys_is_set_less(self, cls: type[MultiDict[str]]) -> None:
304340
d = cls([("key", "value1")])
305341

0 commit comments

Comments
 (0)