Skip to content

Commit 897b030

Browse files
authored
[clang][dep-scan] Resolve lexer crash from a permutation of invalid tokens (llvm#142452)
Sometimes, when a user writes invalid code, the minimization used for scanning can create a stream of tokens that is invalid at lex time. This patch protects against the case where there are valid (non-c++20) import directives discovered in the middle of an invalid `import` declaration. Mostly authored by: @akyrtzi resolves: rdar://152335844
1 parent 8fa440a commit 897b030

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

clang/lib/Lex/DependencyDirectivesScanner.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,15 @@ bool Scanner::lexModuleDirectiveBody(DirectiveKind Kind, const char *&First,
496496
const char *const End) {
497497
const char *DirectiveLoc = Input.data() + CurDirToks.front().Offset;
498498
for (;;) {
499+
// Keep a copy of the First char incase it needs to be reset.
500+
const char *Previous = First;
499501
const dependency_directives_scan::Token &Tok = lexToken(First, End);
502+
if ((Tok.is(tok::hash) || Tok.is(tok::at)) &&
503+
(Tok.Flags & clang::Token::StartOfLine)) {
504+
CurDirToks.pop_back();
505+
First = Previous;
506+
return false;
507+
}
500508
if (Tok.is(tok::eof))
501509
return reportError(
502510
DirectiveLoc,
@@ -846,6 +854,7 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) {
846854
if (*First == '@')
847855
return lexAt(First, End);
848856

857+
// Handle module directives for C++20 modules.
849858
if (*First == 'i' || *First == 'e' || *First == 'm')
850859
return lexModule(First, End);
851860

clang/unittests/Lex/DependencyDirectivesScannerTest.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,13 +677,28 @@ TEST(MinimizeSourceToDependencyDirectivesTest, EmptyIncludesAndImports) {
677677
Out.data());
678678
}
679679

680-
TEST(MinimizeSourceToDependencyDirectivesTest, AtImportFailures) {
680+
TEST(MinimizeSourceToDependencyDirectivesTest, ImportFailures) {
681681
SmallVector<char, 128> Out;
682682

683683
ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import A\n", Out));
684684
ASSERT_FALSE(
685685
minimizeSourceToDependencyDirectives("@import MACRO(A);\n", Out));
686686
ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import \" \";\n", Out));
687+
688+
ASSERT_FALSE(minimizeSourceToDependencyDirectives("import <Foo.h>\n"
689+
"@import Foo;",
690+
Out));
691+
EXPECT_STREQ("@import Foo;\n", Out.data());
692+
693+
ASSERT_FALSE(
694+
minimizeSourceToDependencyDirectives("import <Foo.h>\n"
695+
"#import <Foo.h>\n"
696+
"@;\n"
697+
"#pragma clang module import Foo",
698+
Out));
699+
EXPECT_STREQ("#import <Foo.h>\n"
700+
"#pragma clang module import Foo\n",
701+
Out.data());
687702
}
688703

689704
TEST(MinimizeSourceToDependencyDirectivesTest, RawStringLiteral) {

0 commit comments

Comments
 (0)