forked from qt-creator/qt-creator
C++: block recursion when parsing subsequent case statements.
A case or a default statement must be followed by another statement. When a such a case (or default) statement is followed immediately by another case (or default) statement, then this would create a linked list, and the parser will recurse to parse such input. In order to prevent the parser running out of stack space while recursing, parse this corner case by blocking parsing a labeled statement as the first statement after a labeled statement. The advantage is that these statements do not form a linked list, so any subsequent visitation of the AST won't run out of stack space either. Change-Id: Id2111a49509132997f5fbe4bb12c92c729ec2522 Task-number: QTCREATORBUG-12673 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com>
This commit is contained in:
committed by
Nikolai Kosjar
parent
f51553b228
commit
5d45e0b69a
15
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
15
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
@@ -3031,7 +3031,7 @@ bool Parser::parseExpressionStatement(StatementAST *&node)
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::parseStatement(StatementAST *&node)
|
bool Parser::parseStatement(StatementAST *&node, bool blockLabeledStatement)
|
||||||
{
|
{
|
||||||
DEBUG_THIS_RULE();
|
DEBUG_THIS_RULE();
|
||||||
switch (LA()) {
|
switch (LA()) {
|
||||||
@@ -3058,6 +3058,8 @@ bool Parser::parseStatement(StatementAST *&node)
|
|||||||
|
|
||||||
case T_CASE:
|
case T_CASE:
|
||||||
case T_DEFAULT:
|
case T_DEFAULT:
|
||||||
|
if (blockLabeledStatement)
|
||||||
|
return false;
|
||||||
return parseLabeledStatement(node);
|
return parseLabeledStatement(node);
|
||||||
|
|
||||||
case T_BREAK:
|
case T_BREAK:
|
||||||
@@ -3126,8 +3128,11 @@ bool Parser::parseStatement(StatementAST *&node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (LA() == T_IDENTIFIER && LA(2) == T_COLON)
|
if (LA() == T_IDENTIFIER && LA(2) == T_COLON) {
|
||||||
|
if (blockLabeledStatement)
|
||||||
|
return false;
|
||||||
return parseLabeledStatement(node);
|
return parseLabeledStatement(node);
|
||||||
|
}
|
||||||
|
|
||||||
return parseExpressionOrDeclarationStatement(node);
|
return parseExpressionOrDeclarationStatement(node);
|
||||||
} // switch
|
} // switch
|
||||||
@@ -3598,7 +3603,7 @@ bool Parser::parseLabeledStatement(StatementAST *&node)
|
|||||||
LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
|
LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
|
||||||
ast->label_token = consumeToken();
|
ast->label_token = consumeToken();
|
||||||
ast->colon_token = consumeToken();
|
ast->colon_token = consumeToken();
|
||||||
parseStatement(ast->statement);
|
parseStatement(ast->statement, /*blockLabeledStatement =*/ true);
|
||||||
node = ast;
|
node = ast;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3608,7 +3613,7 @@ bool Parser::parseLabeledStatement(StatementAST *&node)
|
|||||||
LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
|
LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
|
||||||
ast->label_token = consumeToken();
|
ast->label_token = consumeToken();
|
||||||
match(T_COLON, &ast->colon_token);
|
match(T_COLON, &ast->colon_token);
|
||||||
parseStatement(ast->statement);
|
parseStatement(ast->statement, /*blockLabeledStatement =*/ true);
|
||||||
node = ast;
|
node = ast;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3618,7 +3623,7 @@ bool Parser::parseLabeledStatement(StatementAST *&node)
|
|||||||
ast->case_token = consumeToken();
|
ast->case_token = consumeToken();
|
||||||
parseConstantExpression(ast->expression);
|
parseConstantExpression(ast->expression);
|
||||||
match(T_COLON, &ast->colon_token);
|
match(T_COLON, &ast->colon_token);
|
||||||
parseStatement(ast->statement);
|
parseStatement(ast->statement, /*blockLabeledStatement =*/ true);
|
||||||
node = ast;
|
node = ast;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
2
src/libs/3rdparty/cplusplus/Parser.h
vendored
2
src/libs/3rdparty/cplusplus/Parser.h
vendored
@@ -142,7 +142,7 @@ public:
|
|||||||
bool parsePtrOperator(PtrOperatorListAST *&node);
|
bool parsePtrOperator(PtrOperatorListAST *&node);
|
||||||
bool parseRelationalExpression(ExpressionAST *&node);
|
bool parseRelationalExpression(ExpressionAST *&node);
|
||||||
bool parseShiftExpression(ExpressionAST *&node);
|
bool parseShiftExpression(ExpressionAST *&node);
|
||||||
bool parseStatement(StatementAST *&node);
|
bool parseStatement(StatementAST *&node, bool blockLabeledStatement = false);
|
||||||
bool parseThisExpression(ExpressionAST *&node);
|
bool parseThisExpression(ExpressionAST *&node);
|
||||||
bool parseBoolLiteral(ExpressionAST *&node);
|
bool parseBoolLiteral(ExpressionAST *&node);
|
||||||
bool parseNumericLiteral(ExpressionAST *&node);
|
bool parseNumericLiteral(ExpressionAST *&node);
|
||||||
|
100006
tests/auto/cplusplus/c99/data/limits-caselabels.c
Normal file
100006
tests/auto/cplusplus/c99/data/limits-caselabels.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -133,6 +133,7 @@ void tst_c99::parse_data()
|
|||||||
|
|
||||||
QTest::newRow("designatedInitializer.1") << "designatedInitializer.1.c" << "";
|
QTest::newRow("designatedInitializer.1") << "designatedInitializer.1.c" << "";
|
||||||
QTest::newRow("designatedInitializer.2") << "designatedInitializer.2.c" << "";
|
QTest::newRow("designatedInitializer.2") << "designatedInitializer.2.c" << "";
|
||||||
|
QTest::newRow("limits-caselabels (QTCREATORBUG-12673)") << "limits-caselabels.c" << "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_c99::parse()
|
void tst_c99::parse()
|
||||||
|
Reference in New Issue
Block a user