Skip to content

Commit 9c86b8b

Browse files
jensjohaCommit Queue
authored andcommitted
[scanner] Fix infinite loop in error recovery
Fixes #60785 Change-Id: Ida0750115e7582ca44b2a49419ed7ab56295caf6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/433701 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent a69ff18 commit 9c86b8b

File tree

6 files changed

+406
-1
lines changed

6 files changed

+406
-1
lines changed

pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,12 @@ abstract class AbstractScanner implements Scanner {
439439
if (previous.isA(TokenType.CLOSE_PAREN)) {
440440
Token closeParen = token.previous!;
441441
Token? candidate = closeParen.previous;
442-
while (candidate != null && candidate.endGroup != closeParen) {
442+
while (candidate != null) {
443+
if (candidate.endGroup == closeParen) break;
444+
if (candidate.isEof) break;
445+
if (candidate.endGroup != null) {
446+
if (candidate.endGroup!.offset > closeParen.offset) break;
447+
}
443448
candidate = candidate.previous;
444449
}
445450
if (candidate?.endGroup == closeParen && candidate!.previous != null) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
void foo(String s) {
2+
switch (s) {
3+
case 'foo') {
4+
print('foo');
5+
} else {
6+
print('bar');
7+
}
8+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
Problems reported:
2+
3+
parser/general/issue_60785.crash:3:15: Expected ':' before this.
4+
case 'foo') {
5+
^
6+
7+
parser/general/issue_60785.crash:3:15: Expected an identifier, but got ')'.
8+
case 'foo') {
9+
^
10+
11+
parser/general/issue_60785.crash:3:10: Expected ';' after this.
12+
case 'foo') {
13+
^^^^^
14+
15+
parser/general/issue_60785.crash:3:15: Unexpected token ')'.
16+
case 'foo') {
17+
^
18+
19+
parser/general/issue_60785.crash:5:5: Expected an identifier, but got 'else'.
20+
} else {
21+
^^^^
22+
23+
parser/general/issue_60785.crash:5:3: Expected ';' after this.
24+
} else {
25+
^
26+
27+
parser/general/issue_60785.crash:5:5: Unexpected token 'else'.
28+
} else {
29+
^^^^
30+
31+
parser/general/issue_60785.crash:2:14: Can't find '}' to match '{'.
32+
switch (s) {
33+
^
34+
35+
beginCompilationUnit(void)
36+
beginMetadataStar(void)
37+
endMetadataStar(0)
38+
beginTopLevelMember(void)
39+
beginTopLevelMethod(UnmatchedToken({), null, null)
40+
handleVoidKeyword(void)
41+
handleIdentifier(foo, topLevelFunctionDeclaration)
42+
handleNoTypeVariables(()
43+
beginFormalParameters((, MemberKind.TopLevelMethod)
44+
beginMetadataStar(String)
45+
endMetadataStar(0)
46+
beginFormalParameter(String, MemberKind.TopLevelMethod, null, null, null)
47+
handleIdentifier(String, typeReference)
48+
handleNoTypeArguments(s)
49+
handleType(String, null)
50+
handleIdentifier(s, formalParameterDeclaration)
51+
handleFormalParameterWithoutValue())
52+
endFormalParameter(null, null, null, s, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
53+
endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
54+
handleAsyncModifier(null, null)
55+
beginBlockFunctionBody({)
56+
beginSwitchStatement(switch)
57+
handleIdentifier(s, expression)
58+
handleNoTypeArguments())
59+
handleNoArguments())
60+
handleSend(s, s)
61+
handleParenthesizedCondition((, null, null)
62+
beginSwitchBlock({)
63+
beginCaseExpression(case)
64+
beginLiteralString('foo')
65+
endLiteralString(0, ))
66+
handleSwitchCaseNoWhenClause('foo')
67+
handleRecoverableError(Message[ExpectedButGot, Expected ':' before this., null, {string: :}], ), ))
68+
endCaseExpression(case, null, :)
69+
beginSwitchCase(0, 1, case)
70+
handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., Try inserting an identifier before ')'., {lexeme: )}], ), ))
71+
handleIdentifier(, expression)
72+
handleNoTypeArguments())
73+
handleNoArguments())
74+
handleSend(, )
75+
handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], 'foo', 'foo')
76+
handleExpressionStatement(), ;)
77+
handleRecoverableError(Message[UnexpectedToken, Unexpected token ')'., null, {lexeme: )}], ), ))
78+
beginBlock({, BlockKind(statement))
79+
handleIdentifier(print, expression)
80+
handleNoTypeArguments(()
81+
beginArguments(()
82+
beginLiteralString('foo')
83+
endLiteralString(0, ))
84+
endArguments(1, (, ))
85+
handleSend(print, ))
86+
handleExpressionStatement(print, ;)
87+
endBlock(1, {, }, BlockKind(statement))
88+
handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got 'else'., Try inserting an identifier before 'else'., {lexeme: else}], else, else)
89+
handleIdentifier(, expression)
90+
handleNoTypeArguments(else)
91+
handleNoArguments(else)
92+
handleSend(, )
93+
handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], }, })
94+
handleExpressionStatement(else, ;)
95+
handleRecoverableError(Message[UnexpectedToken, Unexpected token 'else'., null, {lexeme: else}], else, else)
96+
beginBlock({, BlockKind(statement))
97+
handleIdentifier(print, expression)
98+
handleNoTypeArguments(()
99+
beginArguments(()
100+
beginLiteralString('bar')
101+
endLiteralString(0, ))
102+
endArguments(1, (, ))
103+
handleSend(print, ))
104+
handleExpressionStatement(print, ;)
105+
endBlock(1, {, }, BlockKind(statement))
106+
endSwitchCase(0, 1, null, null, 4, case, })
107+
endSwitchBlock(1, {, })
108+
endSwitchStatement(switch, })
109+
endBlockFunctionBody(1, {, })
110+
endTopLevelMethod(void, null, })
111+
endTopLevelDeclaration(})
112+
handleErrorToken(UnmatchedToken({))
113+
handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
114+
endCompilationUnit(1, )

0 commit comments

Comments
 (0)