mirror of
https://github.com/python/cpython.git
synced 2026-06-27 19:36:07 +00:00
[3.14] gh-145105: Fix crash in csv.reader with re-entrant iterator (GH-145106) (#148404)
gh-145105: Fix crash in csv.reader with re-entrant iterator (GH-145106)
When a custom iterator calls next() on the same csv.reader from
within __next__, the inner iteration sets self->fields to NULL.
The outer iteration then crashes in parse_save_field() by passing
NULL to PyList_Append.
Add a guard after PyIter_Next() to detect that fields was set to
NULL by a re-entrant call, and raise csv.Error instead of crashing.
(cherry picked from commit 20994b1809)
Co-authored-by: Ramin Farajpour Cami <ramin.blackhat@gmail.com>
This commit is contained in:
parent
d6be9fb077
commit
4f8a77bf3f
3 changed files with 35 additions and 0 deletions
|
|
@ -553,6 +553,33 @@ def test_roundtrip_escaped_unquoted_newlines(self):
|
|||
self.assertEqual(row, rows[i])
|
||||
|
||||
|
||||
def test_reader_reentrant_iterator(self):
|
||||
# gh-145105: re-entering the reader from the iterator must not crash.
|
||||
class ReentrantIter:
|
||||
def __init__(self):
|
||||
self.reader = None
|
||||
self.n = 0
|
||||
def __iter__(self):
|
||||
return self
|
||||
def __next__(self):
|
||||
self.n += 1
|
||||
if self.n == 1:
|
||||
try:
|
||||
next(self.reader)
|
||||
except StopIteration:
|
||||
pass
|
||||
return "a,b"
|
||||
if self.n == 2:
|
||||
return "x"
|
||||
raise StopIteration
|
||||
|
||||
it = ReentrantIter()
|
||||
reader = csv.reader(it)
|
||||
it.reader = reader
|
||||
with self.assertRaises(csv.Error):
|
||||
next(reader)
|
||||
|
||||
|
||||
class TestDialectRegistry(unittest.TestCase):
|
||||
def test_registry_badargs(self):
|
||||
self.assertRaises(TypeError, csv.list_dialects, None)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Fix crash in :mod:`csv` reader when iterating with a re-entrant iterator
|
||||
that calls :func:`next` on the same reader from within ``__next__``.
|
||||
|
|
@ -965,6 +965,12 @@ Reader_iternext_lock_held(PyObject *op)
|
|||
Py_DECREF(lineobj);
|
||||
return NULL;
|
||||
}
|
||||
if (self->fields == NULL) {
|
||||
PyErr_SetString(module_state->error_obj,
|
||||
"iterator has already advanced the reader");
|
||||
Py_DECREF(lineobj);
|
||||
return NULL;
|
||||
}
|
||||
++self->line_num;
|
||||
kind = PyUnicode_KIND(lineobj);
|
||||
data = PyUnicode_DATA(lineobj);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue