[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:
Miss Islington (bot) 2026-04-12 00:46:26 +02:00 committed by GitHub
parent d6be9fb077
commit 4f8a77bf3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 0 deletions

View file

@ -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)

View file

@ -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__``.

View file

@ -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);