Skip to content

Commit 7ba94ca

Browse files
committed
gh-109638: Avoid pathological backtracking in csv.Sniffer
1 parent 23b2b40 commit 7ba94ca

3 files changed

Lines changed: 9 additions & 1 deletion

File tree

Lib/csv.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def _guess_quote_and_delimiter(self, data, delimiters):
331331
# if we see an extra quote between delimiters, we've got a
332332
# double quoted format
333333
dq_regexp = re.compile(
334-
r"((%(delim)s)|^)\W*%(quote)s[^%(delim)s\n]*%(quote)s[^%(delim)s\n]*%(quote)s\W*((%(delim)s)|$)" % \
334+
r"((%(delim)s)|^)\W*%(quote)s[^%(delim)s%(quote)s\n]*%(quote)s[^%(delim)s\n]*%(quote)s\W*((%(delim)s)|$)" % \
335335
{'delim':re.escape(delim), 'quote':quotechar}, re.MULTILINE)
336336

337337

Lib/test/test_csv.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,12 @@ def test_delimiters(self):
15011501
self.assertEqual(dialect.delimiter, ',')
15021502
self.assertEqual(dialect.quotechar, '"')
15031503

1504+
def test_sniff_regex_backtracking(self):
1505+
# gh-109638: this artificial sample used to take minutes.
1506+
sniffer = csv.Sniffer()
1507+
sample = '"",' * 100 + '"' * 100 + '0' + '"' * 100 + '0'
1508+
self.assertEqual(sniffer.sniff(sample).delimiter, ',')
1509+
15041510
def test_doublequote(self):
15051511
sniffer = csv.Sniffer()
15061512
dialect = sniffer.sniff(self.header1)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Prevent pathological regular expression backtracking in :class:`csv.Sniffer`
2+
when detecting doubled quote characters.

0 commit comments

Comments
 (0)