mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
[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 be5af997f3)
Co-authored-by: Mikhail Efimov <efimov.mikhail@gmail.com>
This commit is contained in:
parent
a975bea9b5
commit
11b5e0b9c2
2 changed files with 41 additions and 19 deletions
|
|
@ -1384,6 +1384,22 @@ def test_map_strict(self):
|
||||||
self.assertRaises(ValueError, tuple,
|
self.assertRaises(ValueError, tuple,
|
||||||
map(pack, (1, 2), (1, 2), 'abc', strict=True))
|
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):
|
def test_map_strict_iterators(self):
|
||||||
x = iter(range(5))
|
x = iter(range(5))
|
||||||
y = [0]
|
y = [0]
|
||||||
|
|
|
||||||
|
|
@ -1501,34 +1501,27 @@ map_next(PyObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_ssize_t nargs = 0;
|
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 *it = PyTuple_GET_ITEM(lz->iters, i);
|
||||||
PyObject *val = Py_TYPE(it)->tp_iternext(it);
|
PyObject *val = Py_TYPE(it)->tp_iternext(it);
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
if (lz->strict) {
|
if (lz->strict) {
|
||||||
goto check;
|
goto check;
|
||||||
}
|
}
|
||||||
goto exit;
|
goto exit_no_result;
|
||||||
}
|
}
|
||||||
stack[i] = val;
|
stack[i] = val;
|
||||||
nargs++;
|
nargs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = _PyObject_VectorcallTstate(tstate, lz->func, stack, nargs, NULL);
|
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:
|
check:
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
||||||
// next() on argument i raised an exception (not StopIteration)
|
// next() on argument i raised an exception (not StopIteration)
|
||||||
return NULL;
|
goto exit_no_result;
|
||||||
}
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
|
@ -1536,9 +1529,10 @@ map_next(PyObject *self)
|
||||||
// ValueError: map() argument 2 is shorter than argument 1
|
// ValueError: map() argument 2 is shorter than argument 1
|
||||||
// ValueError: map() argument 3 is shorter than arguments 1-2
|
// ValueError: map() argument 3 is shorter than arguments 1-2
|
||||||
const char* plural = i == 1 ? " " : "s 1-";
|
const char* plural = i == 1 ? " " : "s 1-";
|
||||||
return PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"map() argument %d is shorter than argument%s%d",
|
"map() argument %d is shorter than argument%s%d",
|
||||||
i + 1, plural, i);
|
i + 1, plural, i);
|
||||||
|
goto exit_no_result;
|
||||||
}
|
}
|
||||||
for (i = 1; i < niters; i++) {
|
for (i = 1; i < niters; i++) {
|
||||||
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
|
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
|
||||||
|
|
@ -1546,21 +1540,33 @@ map_next(PyObject *self)
|
||||||
if (val) {
|
if (val) {
|
||||||
Py_DECREF(val);
|
Py_DECREF(val);
|
||||||
const char* plural = i == 1 ? " " : "s 1-";
|
const char* plural = i == 1 ? " " : "s 1-";
|
||||||
return PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"map() argument %d is longer than argument%s%d",
|
"map() argument %d is longer than argument%s%d",
|
||||||
i + 1, plural, i);
|
i + 1, plural, i);
|
||||||
|
goto exit_no_result;
|
||||||
}
|
}
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
||||||
// next() on argument i raised an exception (not StopIteration)
|
// next() on argument i raised an exception (not StopIteration)
|
||||||
return NULL;
|
goto exit_no_result;
|
||||||
}
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
// Argument i is exhausted. So far so good...
|
// Argument i is exhausted. So far so good...
|
||||||
}
|
}
|
||||||
// All arguments are exhausted. Success!
|
// 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 *
|
static PyObject *
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue