GeezerVison is showing github.com — bpo-40661: Fix segfault when parsing invalid input by lysnikolaou · Pull Request #20165 · python/cpython
Conversation
lysnikolaou
commented
May 17, 2020
•
edited by bedevere-bot
Loading
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Fix segfaults when parsing very complex invalid input, like
`import äˆ ð£„¯ð¢·žð±‹á”€ð””ð‘©±å®ä±¬ð©¾\nð—¶½`.
Initially reported by @pablogsal.
This is not really needed, but it's nice to have, so that we don't
unnecessariy call `_PyPegen_fill_token` when there are errors and
the parser will abort anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was experimenting with the reproducer locally and might have discovered a more minimalist solution. I'm not certain as to whether this approach is any better or worse (my experience and knowledge w/ the parser is very limited), but this also seems to address the segfault:
diff --git a/Lib/test/test_peg_parser.py b/Lib/test/test_peg_parser.py
index 9614e45799..05de8582e7 100644
--- a/Lib/test/test_peg_parser.py
+++ b/Lib/test/test_peg_parser.py
@@ -591,6 +591,7 @@ FAIL_TEST_CASES = [
("f-string_single_closing_brace", "f'}'"),
("from_import_invalid", "from import import a"),
("from_import_trailing_comma", "from a import b,"),
+ ("import_very_complex", "import äˆ ð£„¯ð¢·žð±‹á”€ð””ð‘©±å®ä±¬ð©¾\nð—¶½"),
# This test case checks error paths involving tokens with uninitialized
# values of col_offset and end_col_offset.
("invalid indentation",
diff --git a/Parser/pegen/pegen.c b/Parser/pegen/pegen.c
index 7f3e4561de..25b8db0982 100644
--- a/Parser/pegen/pegen.c
+++ b/Parser/pegen/pegen.c
@@ -758,6 +758,9 @@ _PyPegen_lookahead(int positive, void *(func)(Parser *), Parser *p)
Token *
_PyPegen_expect_token(Parser *p, int type)
{
+ if (p->error_indicator) {
+ return NULL;
+ }
if (p->mark == p->fill) {
Would it make any sense to check the error indicator at the beginning of _PyPegen_expect_token()?
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
lysnikolaou
commented
May 18, 2020
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
|
IMHO the solution Pablo found might be a bit more verbose and add 3 lines of code per alternative, but it makes more sense and is something we should have done, when we initially replaced setjmp with p->error_indicator. We generally want the parser to abort as quickly as possible, when there's an error, and that includes not going through the other alternatives of the rule that fails and all those above it in call tree.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
|
@aeros What would really be helpful here is to understand the sequence of events that happens when the parser encounters that input, and compare it to what happens on similar ASCII input like import a ?. What path (presumably involving the tokenizer) is taken differently?
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
pablogsal
commented
May 18, 2020
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
What path (presumably involving the tokenizer) is taken differently?
The difference is that when the import is not ascii, this code path is taken:
https://github.com/python/cpython/blob/master/Parser/pegen/pegen.c#L90-L105
and the call to id2 = _PyObject_FastCall(p->normalize, args, 2); is the one that fails because when we enter that call, we already have an exception set from tokenize_error, which is the exception that should be reported.
So basically: for ASCII characters there is one call less that makes the error surface without problems, but with non-ASCII characters, there is some call into Python code that fails because is done with an exception already set.
This can happen in so many other ways, so I think this PR is the safest thing to do because we make sure that nothing more is tried (and therefore no other calls can occur) when the error indicator is set.
|
aeros reacted with thumbs up emoji
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
("f-string_single_closing_brace", "f'}'"),
|
|
|
("from_import_invalid", "from import import a"),
|
|
|
("from_import_trailing_comma", "from a import b,"),
|
|
|
("import_non_ascii_syntax_error", "import ä £"),
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add this to test_syntax as well? This file will likely go away when we don't have two parsers to compare against anymore.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have pushed this myself in commit 7353b6c
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
lysnikolaou reacted with thumbs up emoji
arturoescaip
pushed a commit
to arturoescaip/cpython
that referenced
this pull request
May 24, 2020
Fix segfaults when parsing very complex invalid input, like `import äˆ ð£„¯ð¢·žð±‹á”€ð””ð‘©±å®ä±¬ð©¾\nð—¶½`.
Co-authored-by: Guido van Rossum <[email protected]>
Co-authored-by: Pablo Galindo <[email protected]>
Reviewers
+1 more reviewer
aeros
aeros left review comments
Reviewers whose approvals may not affect merge requirements
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|