Skip to content

Commit 3b2f3d9

Browse files
committed
[clang][dep-scan] Resolve lexer crash from a permutation of invalid tokens
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 theres valid import directives discovered in the middle of an invalid `import` declaration. resolves: rdar://152335844
1 parent 8e2641a commit 3b2f3d9

File tree

4 files changed

+25
-4
lines changed

4 files changed

+25
-4
lines changed

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,8 @@ def err_dep_source_scanner_missing_semi_after_at_import : Error<
10291029
"could not find ';' after @import">;
10301030
def err_dep_source_scanner_unexpected_tokens_at_import : Error<
10311031
"unexpected extra tokens at end of @import declaration">;
1032-
1032+
def err_dep_source_scanner_unexpected_tokens_in_directive_body
1033+
: Error<"unexpected extra tokens inside declaration">;
10331034
}
10341035

10351036
def err_pp_double_begin_pragma_unsafe_buffer_usage :

clang/lib/Lex/DependencyDirectivesScanner.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@ bool Scanner::lexModuleDirectiveBody(DirectiveKind Kind, const char *&First,
503503
diag::err_dep_source_scanner_missing_semi_after_at_import);
504504
if (Tok.is(tok::semi))
505505
break;
506+
if (Tok.is(tok::hash) || Tok.is(tok::at))
507+
return reportError(
508+
First,
509+
diag::err_dep_source_scanner_unexpected_tokens_in_directive_body);
506510
}
507511
pushDirective(Kind);
508512
skipWhitespace(First, End);
@@ -846,6 +850,7 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) {
846850
if (*First == '@')
847851
return lexAt(First, End);
848852

853+
// Handle module directives for C++20 modules.
849854
if (*First == 'i' || *First == 'e' || *First == 'm')
850855
return lexModule(First, End);
851856

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %clang_cc1 -verify -print-dependency-directives-minimized-source %s 2>&1
2+
3+
import <invalid.h>
4+
#import "invalid.h" // expected-error {{unexpected extra tokens inside declaration}}
5+
@;
6+
#pragma clang module import invalid

clang/unittests/Lex/DependencyDirectivesScannerTest.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static bool minimizeSourceToDependencyDirectives(
3333

3434
return false;
3535
}
36-
36+
// Returns false on successful minimization.
3737
static bool minimizeSourceToDependencyDirectives(StringRef Input,
3838
SmallVectorImpl<char> &Out) {
3939
SmallVector<dependency_directives_scan::Token, 16> Tokens;
@@ -677,13 +677,22 @@ TEST(MinimizeSourceToDependencyDirectivesTest, EmptyIncludesAndImports) {
677677
Out.data());
678678
}
679679

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

683-
ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import A\n", Out));
683+
// Minimization can recover, and let the real compilation fail.
684684
ASSERT_FALSE(
685685
minimizeSourceToDependencyDirectives("@import MACRO(A);\n", Out));
686686
ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import \" \";\n", Out));
687+
688+
ASSERT_FALSE(minimizeSourceToDependencyDirectives("import\n", Out));
689+
EXPECT_STREQ("<TokBeforeEOF>\n", Out.data());
690+
691+
// Minimization cannot recover.
692+
ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import A\n", Out));
693+
ASSERT_TRUE(minimizeSourceToDependencyDirectives("import <Foo.h>\n"
694+
"#include \"Foo.h\"",
695+
Out));
687696
}
688697

689698
TEST(MinimizeSourceToDependencyDirectivesTest, RawStringLiteral) {

0 commit comments

Comments
 (0)