Skip to content

Commit 8526218

Browse files
gh-157379: Fix crash in csv.reader with re-entrant iterator at end of input
The gh-145105 guard only runs after the input iterator returns a line. When a re-entrant call leaves a quoted field open and the outer call then reaches the end of input, parse_save_field() appended to the NULL fields list. Raise csv.Error in that branch too.
1 parent c215919 commit 8526218

3 files changed

Lines changed: 30 additions & 0 deletions

File tree

Lib/test/test_csv.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,30 @@ def __next__(self):
598598
with self.assertRaises(csv.Error):
599599
next(reader)
600600

601+
def test_reader_reentrant_iterator_eof_in_quoted_field(self):
602+
# gh-157379: the re-entrant call leaves an open quoted field, then
603+
# the outer call reaches the end of input.
604+
class ReentrantIter:
605+
def __init__(self):
606+
self.reader = None
607+
self.n = 0
608+
def __iter__(self):
609+
return self
610+
def __next__(self):
611+
self.n += 1
612+
if self.n == 1:
613+
next(self.reader)
614+
raise StopIteration
615+
if self.n == 2:
616+
return '"x'
617+
raise StopIteration
618+
619+
it = ReentrantIter()
620+
reader = csv.reader(it)
621+
it.reader = reader
622+
with self.assertRaises(csv.Error):
623+
next(reader)
624+
601625

602626
class TestDialectRegistry(unittest.TestCase):
603627
def test_registry_badargs(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash in :mod:`csv` reader when a re-entrant iterator reaches the end
2+
of input while a quoted field is still open.

Modules/_csv.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,10 @@ Reader_iternext_lock_held(PyObject *op)
10291029
if (self->dialect->strict)
10301030
PyErr_SetString(module_state->error_obj,
10311031
"unexpected end of data");
1032+
else if (self->fields == NULL)
1033+
PyErr_SetString(module_state->error_obj,
1034+
"iterator has already advanced "
1035+
"the reader");
10321036
else if (parse_save_field(self) >= 0)
10331037
break;
10341038
}

0 commit comments

Comments
 (0)