C++: Fix crash with invalid raw string literal

While parsing a document Bind::asStringLiteral() Token::spell() was
called for a raw string literal token with a Token::literal nullptr.

This is due scanRawStringLiteral() not properly aborting for
invalid/incomplete code and that the code paths handling
multi-line-raw-strings were not limited to the highlighting case.

Address both cases.

Task-number: QTCREATORBUG-18941
Change-Id: I489d288ccbd7b59be396dada846613ff555436cf
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Nikolai Kosjar
2017-09-19 14:36:21 +02:00
parent 0bf27af0a7
commit 76006a1353
3 changed files with 31 additions and 6 deletions

View File

@@ -211,7 +211,7 @@ void Lexer::scan_helper(Token *tok)
_state = 0; _state = 0;
scanCppComment(originalKind); scanCppComment(originalKind);
return; return;
} else if (isRawStringLiteral(s._tokenKind)) { } else if (!control() && isRawStringLiteral(s._tokenKind)) {
tok->f.kind = s._tokenKind; tok->f.kind = s._tokenKind;
if (scanUntilRawStringLiteralEndSimple()) if (scanUntilRawStringLiteralEndSimple())
_state = 0; _state = 0;
@@ -755,13 +755,17 @@ void Lexer::scanRawStringLiteral(Token *tok, unsigned char hint)
yyinp(); yyinp();
} else if (_yychar == ')') { } else if (_yychar == ')') {
yyinp(); yyinp();
if (delimLength == -1) if (delimLength == -1) {
break; tok->f.kind = T_ERROR;
return;
}
closingDelimCandidate = _currentChar; closingDelimCandidate = _currentChar;
} else { } else {
if (delimLength == -1) { if (delimLength == -1) {
if (_yychar == '\\' || std::isspace(_yychar)) if (_yychar == '\\' || std::isspace(_yychar)) {
break; tok->f.kind = T_ERROR;
return;
}
yyinp(); yyinp();
} else { } else {
if (!closingDelimCandidate) { if (!closingDelimCandidate) {
@@ -804,7 +808,7 @@ void Lexer::scanRawStringLiteral(Token *tok, unsigned char hint)
else else
tok->f.kind = T_RAW_STRING_LITERAL; tok->f.kind = T_RAW_STRING_LITERAL;
if (!closed) if (!control() && !closed)
s._tokenKind = tok->f.kind; s._tokenKind = tok->f.kind;
} }

View File

@@ -366,6 +366,14 @@ void tst_SimpleLexer::literals_data()
<< T_RAW_STRING_LITERAL << T_RAW_STRING_LITERAL
; ;
QTest::newRow("raw-string-literals") << source << expectedTokenKindList; QTest::newRow("raw-string-literals") << source << expectedTokenKindList;
source = "R\"\\" ;
expectedTokenKindList = TokenKindList() << T_ERROR;
QTest::newRow("invalid-raw-string-literals1") << source << expectedTokenKindList;
source = "R\")" ;
expectedTokenKindList = TokenKindList() << T_ERROR;
QTest::newRow("invalid-raw-string-literals2") << source << expectedTokenKindList;
} }
void tst_SimpleLexer::preprocessor() void tst_SimpleLexer::preprocessor()

View File

@@ -48,6 +48,8 @@ private slots:
void astPathOnGeneratedTokens(); void astPathOnGeneratedTokens();
void typeMatcher(); void typeMatcher();
void doNotCrashForInvalidRawString();
}; };
void tst_Misc::diagnosticClient_error() void tst_Misc::diagnosticClient_error()
@@ -266,5 +268,16 @@ void tst_Misc::typeMatcher()
} }
} }
void tst_Misc::doNotCrashForInvalidRawString()
{
const QByteArray src("\n"
"void f() { enum { Size = sizeof(R\"[^\\s]+([^]+)*\") }; }"
"}\n"
);
Document::Ptr doc = Document::create("crash");
doc->setUtf8Source(src);
doc->check();
}
QTEST_MAIN(tst_Misc) QTEST_MAIN(tst_Misc)
#include "tst_misc.moc" #include "tst_misc.moc"