https://github.com/python/cpython/commit/be5af997f3461eee638645396866d9cd7acf18fb
commit: be5af997f3461eee638645396866d9cd7acf18fb
branch: main
author: Mikhail Efimov <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2025-10-24T21:29:16+05:30
summary:
gh-140517: fix leak in `map_next` in strict mode (#140543)
files:
M Lib/test/test_builtin.py
M Python/bltinmodule.c
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 034cd5f7f9e89f..fe3e391a7f5ba1 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -1385,6 +1385,22 @@ def test_map_strict(self):
self.assertRaises(ValueError, tuple,
map(pack, (1, 2), (1, 2), 'abc', strict=True))
+ # gh-140517: Testing refleaks with mortal objects.
+ t1 = (None, object())
+ t2 = (object(), object())
+ t3 = (object(),)
+
+ self.assertRaises(ValueError, tuple,
+ map(pack, t1, 'a', strict=True))
+ self.assertRaises(ValueError, tuple,
+ map(pack, t1, t2, 'a', strict=True))
+ self.assertRaises(ValueError, tuple,
+ map(pack, t1, t2, t3, strict=True))
+ self.assertRaises(ValueError, tuple,
+ map(pack, 'a', t1, strict=True))
+ self.assertRaises(ValueError, tuple,
+ map(pack, 'a', t2, t3, strict=True))
+
def test_map_strict_iterators(self):
x = iter(range(5))
y = [0]
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 64249177eec5f2..f6fadd936bb8ff 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1501,34 +1501,27 @@ map_next(PyObject *self)
}
Py_ssize_t nargs = 0;
- for (i=0; i < niters; i++) {
+ for (i = 0; i < niters; i++) {
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
PyObject *val = Py_TYPE(it)->tp_iternext(it);
if (val == NULL) {
if (lz->strict) {
goto check;
}
- goto exit;
+ goto exit_no_result;
}
stack[i] = val;
nargs++;
}
result = _PyObject_VectorcallTstate(tstate, lz->func, stack, nargs, NULL);
+ goto exit;
-exit:
- for (i=0; i < nargs; i++) {
- Py_DECREF(stack[i]);
- }
- if (stack != small_stack) {
- PyMem_Free(stack);
- }
- return result;
check:
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
// next() on argument i raised an exception (not StopIteration)
- return NULL;
+ goto exit_no_result;
}
PyErr_Clear();
}
@@ -1536,9 +1529,10 @@ map_next(PyObject *self)
// ValueError: map() argument 2 is shorter than argument 1
// ValueError: map() argument 3 is shorter than arguments 1-2
const char* plural = i == 1 ? " " : "s 1-";
- return PyErr_Format(PyExc_ValueError,
- "map() argument %d is shorter than argument%s%d",
- i + 1, plural, i);
+ PyErr_Format(PyExc_ValueError,
+ "map() argument %d is shorter than argument%s%d",
+ i + 1, plural, i);
+ goto exit_no_result;
}
for (i = 1; i < niters; i++) {
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
@@ -1546,21 +1540,33 @@ map_next(PyObject *self)
if (val) {
Py_DECREF(val);
const char* plural = i == 1 ? " " : "s 1-";
- return PyErr_Format(PyExc_ValueError,
- "map() argument %d is longer than
argument%s%d",
- i + 1, plural, i);
+ PyErr_Format(PyExc_ValueError,
+ "map() argument %d is longer than argument%s%d",
+ i + 1, plural, i);
+ goto exit_no_result;
}
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
// next() on argument i raised an exception (not StopIteration)
- return NULL;
+ goto exit_no_result;
}
PyErr_Clear();
}
// Argument i is exhausted. So far so good...
}
// All arguments are exhausted. Success!
- goto exit;
+
+exit_no_result:
+ assert(result == NULL);
+
+exit:
+ for (i = 0; i < nargs; i++) {
+ Py_DECREF(stack[i]);
+ }
+ if (stack != small_stack) {
+ PyMem_Free(stack);
+ }
+ return result;
}
static PyObject *
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]