Skip to content

Commit 89d4062

Browse files
Leak fixed
1 parent 161b306 commit 89d4062

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

Lib/test/test_builtin.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,23 @@ def __next__(self):
14571457
l8 = self.iter_error(map(pack, Iter(3), "AB", strict=True), ValueError)
14581458
self.assertEqual(l8, [(2, "A"), (1, "B")])
14591459

1460+
# gh-140517: fix refcount leak
1461+
def test_map_strict_noleak(self):
1462+
t1 = (None, object())
1463+
t2 = (object(), object())
1464+
t3 = (object(),)
1465+
1466+
self.assertRaises(ValueError, tuple,
1467+
map(pack, t1, 'a', strict=True))
1468+
self.assertRaises(ValueError, tuple,
1469+
map(pack, t1, t2, 'a', strict=True))
1470+
self.assertRaises(ValueError, tuple,
1471+
map(pack, t1, t2, t3, strict=True))
1472+
self.assertRaises(ValueError, tuple,
1473+
map(pack, 'a', t1, strict=True))
1474+
self.assertRaises(ValueError, tuple,
1475+
map(pack, 'a', t2, t3, strict=True))
1476+
14601477
def test_max(self):
14611478
self.assertEqual(max('123123'), '3')
14621479
self.assertEqual(max(1, 2, 3), 3)

Python/bltinmodule.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,52 +1515,56 @@ map_next(PyObject *self)
15151515
}
15161516

15171517
result = _PyObject_VectorcallTstate(tstate, lz->func, stack, nargs, NULL);
1518+
goto exit;
15181519

1519-
exit:
1520-
for (i=0; i < nargs; i++) {
1521-
Py_DECREF(stack[i]);
1522-
}
1523-
if (stack != small_stack) {
1524-
PyMem_Free(stack);
1525-
}
1526-
return result;
15271520
check:
15281521
if (PyErr_Occurred()) {
15291522
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
15301523
// next() on argument i raised an exception (not StopIteration)
1531-
return NULL;
1524+
// result is NULL;
1525+
goto exit;
15321526
}
15331527
PyErr_Clear();
15341528
}
15351529
if (i) {
15361530
// ValueError: map() argument 2 is shorter than argument 1
15371531
// ValueError: map() argument 3 is shorter than arguments 1-2
15381532
const char* plural = i == 1 ? " " : "s 1-";
1539-
return PyErr_Format(PyExc_ValueError,
1540-
"map() argument %d is shorter than argument%s%d",
1541-
i + 1, plural, i);
1533+
result = PyErr_Format(PyExc_ValueError,
1534+
"map() argument %d is shorter than argument%s%d",
1535+
i + 1, plural, i);
1536+
goto exit;
15421537
}
15431538
for (i = 1; i < niters; i++) {
15441539
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
15451540
PyObject *val = (*Py_TYPE(it)->tp_iternext)(it);
15461541
if (val) {
15471542
Py_DECREF(val);
15481543
const char* plural = i == 1 ? " " : "s 1-";
1549-
return PyErr_Format(PyExc_ValueError,
1550-
"map() argument %d is longer than argument%s%d",
1551-
i + 1, plural, i);
1544+
result = PyErr_Format(PyExc_ValueError,
1545+
"map() argument %d is longer than argument%s%d",
1546+
i + 1, plural, i);
1547+
goto exit;
15521548
}
15531549
if (PyErr_Occurred()) {
15541550
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
15551551
// next() on argument i raised an exception (not StopIteration)
1556-
return NULL;
1552+
// result is NULL;
1553+
goto exit;
15571554
}
15581555
PyErr_Clear();
15591556
}
15601557
// Argument i is exhausted. So far so good...
15611558
}
15621559
// All arguments are exhausted. Success!
1563-
goto exit;
1560+
exit:
1561+
for (i=0; i < nargs; i++) {
1562+
Py_DECREF(stack[i]);
1563+
}
1564+
if (stack != small_stack) {
1565+
PyMem_Free(stack);
1566+
}
1567+
return result;
15641568
}
15651569

15661570
static PyObject *

0 commit comments

Comments
 (0)