From 417206a05c4545bde96c2bbbea92b53e6cac0d48 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Wed, 30 Nov 2022 11:36:06 +0000 Subject: gh-99891: Fix infinite recursion in the tokenizer when showing warnings (GH-99893) Automerge-Triggered-By: GH:pablogsal --- Lib/test/test_source_encoding.py | 12 ++++++++++++ .../2022-11-30-11-09-40.gh-issue-99891.9VomwB.rst | 3 +++ Parser/tokenizer.c | 8 ++++++++ Parser/tokenizer.h | 1 + 4 files changed, 24 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-11-30-11-09-40.gh-issue-99891.9VomwB.rst diff --git a/Lib/test/test_source_encoding.py b/Lib/test/test_source_encoding.py index cfc4b13..b05173a 100644 --- a/Lib/test/test_source_encoding.py +++ b/Lib/test/test_source_encoding.py @@ -160,6 +160,18 @@ class MiscSourceEncodingTest(unittest.TestCase): finally: os.unlink(TESTFN) + def test_tokenizer_fstring_warning_in_first_line(self): + source = "0b1and 2" + with open(TESTFN, "w") as fd: + fd.write("{}".format(source)) + try: + retcode, stdout, stderr = script_helper.assert_python_ok(TESTFN) + self.assertIn(b"SyntaxWarning: invalid binary litera", stderr) + self.assertEqual(stderr.count(source.encode()), 1) + finally: + os.unlink(TESTFN) + + class AbstractSourceEncodingTest: def test_default_coding(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-30-11-09-40.gh-issue-99891.9VomwB.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-30-11-09-40.gh-issue-99891.9VomwB.rst new file mode 100644 index 0000000..20cd361 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-30-11-09-40.gh-issue-99891.9VomwB.rst @@ -0,0 +1,3 @@ +Fix a bug in the tokenizer that could cause infinite recursion when showing +syntax warnings that happen in the first line of the source. Patch by Pablo +Galindo diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index ce72e15..463c0e0 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -97,6 +97,7 @@ tok_new(void) tok->async_def_nl = 0; tok->interactive_underflow = IUNDERFLOW_NORMAL; tok->str = NULL; + tok->report_warnings = 1; #ifdef Py_DEBUG tok->debug = _Py_GetConfig()->parser_debug; #endif @@ -1201,6 +1202,10 @@ indenterror(struct tok_state *tok) static int parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...) { + if (!tok->report_warnings) { + return 0; + } + PyObject *errmsg; va_list vargs; va_start(vargs, format); @@ -2239,6 +2244,9 @@ _PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) } } struct token token; + // We don't want to report warnings here because it could cause infinite recursion + // if fetching the encoding shows a warning. + tok->report_warnings = 0; while (tok->lineno < 2 && tok->done == E_OK) { _PyTokenizer_Get(tok, &token); } diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 2542d30..16a94d5 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -92,6 +92,7 @@ struct tok_state { NEWLINE token after it. */ /* How to proceed when asked for a new token in interactive mode */ enum interactive_underflow_t interactive_underflow; + int report_warnings; #ifdef Py_DEBUG int debug; #endif -- cgit v0.12