Skip to content

Commit b6a8921

Browse files
committed
gh-103503: prevent map iterator stack overflow
1 parent bc6749c commit b6a8921

2 files changed

Lines changed: 17 additions & 5 deletions

File tree

Lib/test/test_builtin.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,14 @@ def badfunc(x):
14321432
raise RuntimeError
14331433
self.assertRaises(RuntimeError, list, map(badfunc, range(5)))
14341434

1435+
it = []
1436+
for _ in range(100_000):
1437+
it = map(int, it)
1438+
with self.assertRaisesRegex(
1439+
RecursionError, r"Stack overflow .* while iterating"
1440+
):
1441+
list(it)
1442+
14351443
def test_map_pickle(self):
14361444
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
14371445
m1 = map(map_char, "Is this the real life?")

Python/bltinmodule.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,11 +1572,16 @@ map_next(PyObject *self)
15721572
{
15731573
mapobject *lz = _mapobject_CAST(self);
15741574
Py_ssize_t i;
1575+
Py_ssize_t nargs = 0;
15751576
PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
1576-
PyObject **stack;
1577+
PyObject **stack = NULL;
15771578
PyObject *result = NULL;
15781579
PyThreadState *tstate = _PyThreadState_GET();
15791580

1581+
if (_Py_EnterRecursiveCallTstate(tstate, " while calling map()")) {
1582+
return NULL;
1583+
}
1584+
15801585
const Py_ssize_t niters = PyTuple_GET_SIZE(lz->iters);
15811586
if (niters <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
15821587
stack = small_stack;
@@ -1585,11 +1590,9 @@ map_next(PyObject *self)
15851590
stack = PyMem_Malloc(niters * sizeof(stack[0]));
15861591
if (stack == NULL) {
15871592
_PyErr_NoMemory(tstate);
1588-
return NULL;
1593+
goto exit;
15891594
}
15901595
}
1591-
1592-
Py_ssize_t nargs = 0;
15931596
for (i = 0; i < niters; i++) {
15941597
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
15951598
PyObject *val = Py_TYPE(it)->tp_iternext(it);
@@ -1652,9 +1655,10 @@ map_next(PyObject *self)
16521655
for (i = 0; i < nargs; i++) {
16531656
Py_DECREF(stack[i]);
16541657
}
1655-
if (stack != small_stack) {
1658+
if (stack != NULL && stack != small_stack) {
16561659
PyMem_Free(stack);
16571660
}
1661+
_Py_LeaveRecursiveCallTstate(tstate);
16581662
return result;
16591663
}
16601664

0 commit comments

Comments
 (0)