https://github.com/python/cpython/commit/11b5e0b9c285c7890ff6b1fee1964f9f810a71df
commit: 11b5e0b9c285c7890ff6b1fee1964f9f810a71df
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2025-10-24T22:00:36+05:30
summary:

[3.14] gh-140517: fix leak in `map_next` in strict mode (GH-140543) (#140554)

gh-140517: fix leak in `map_next` in strict mode (GH-140543)
(cherry picked from commit be5af997f3461eee638645396866d9cd7acf18fb)

Co-authored-by: Mikhail Efimov <[email protected]>

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 413429f51096c5..5e9b087db91aad 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -1384,6 +1384,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 4ab67bdee1d6ba..9b9e56a5b117c0 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]

Reply via email to