Skip to content

Commit 16c7829

Browse files
Queen Dela Cruzkadircet
Queen Dela Cruz
authored andcommitted
[clangd] Check if macro is already in the IdentifierTable before loading it
Having nested macros in the C code could cause clangd to fail an assert in clang::Preprocessor::setLoadedMacroDirective() and crash. #1 0x00000000007ace30 PrintStackTraceSignalHandler(void*) /qdelacru/llvm-project/llvm/lib/Support/Unix/Signals.inc:632:1 rust-lang#2 0x00000000007aaded llvm::sys::RunSignalHandlers() /qdelacru/llvm-project/llvm/lib/Support/Signals.cpp:76:20 rust-lang#3 0x00000000007ac7c1 SignalHandler(int) /qdelacru/llvm-project/llvm/lib/Support/Unix/Signals.inc:407:1 rust-lang#4 0x00007f096604db20 __restore_rt (/lib64/libpthread.so.0+0x12b20) rust-lang#5 0x00007f0964b307ff raise (/lib64/libc.so.6+0x377ff) rust-lang#6 0x00007f0964b1ac35 abort (/lib64/libc.so.6+0x21c35) rust-lang#7 0x00007f0964b1ab09 _nl_load_domain.cold.0 (/lib64/libc.so.6+0x21b09) rust-lang#8 0x00007f0964b28de6 (/lib64/libc.so.6+0x2fde6) rust-lang#9 0x0000000001004d1a clang::Preprocessor::setLoadedMacroDirective(clang::IdentifierInfo*, clang::MacroDirective*, clang::MacroDirective*) /qdelacru/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp:116:5 An example of the code that causes the assert failure: ``` ... ``` During code completion in clangd, the macros will be loaded in loadMainFilePreambleMacros() by iterating over the macro names and calling PreambleIdentifiers->get(). Since these macro names are store in a StringSet (has StringMap underlying container), the order of the iterator is not guaranteed to be same as the order seen in the source code. When clangd is trying to resolve nested macros it sometimes attempts to load them out of order which causes a macro to be stored twice. In the example above, ECHO2 macro gets resolved first, but since it uses another macro that has not been resolved it will try to resolve/store that as well. Now there are two MacroDirectives stored in the Preprocessor, ECHO and ECHO2. When clangd tries to load the next macro, ECHO, the preprocessor fails an assert in clang::Preprocessor::setLoadedMacroDirective() because there is already a MacroDirective stored for that macro name. In this diff, I check if the macro is already inside the IdentifierTable and if it is skip it so that it is not resolved twice. Reviewed By: kadircet Differential Revision: https://reviews.llvm.org/D101870
1 parent 207b08a commit 16c7829

File tree

2 files changed

+16
-2
lines changed

2 files changed

+16
-2
lines changed

Diff for: clang-tools-extra/clangd/CodeComplete.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -1105,14 +1105,19 @@ void loadMainFilePreambleMacros(const Preprocessor &PP,
11051105
ExternalPreprocessorSource *PreambleMacros = PP.getExternalSource();
11061106
// As we have the names of the macros, we can look up their IdentifierInfo
11071107
// and then use this to load just the macros we want.
1108+
const auto &ITable = PP.getIdentifierTable();
11081109
IdentifierInfoLookup *PreambleIdentifiers =
1109-
PP.getIdentifierTable().getExternalIdentifierLookup();
1110+
ITable.getExternalIdentifierLookup();
1111+
11101112
if (!PreambleIdentifiers || !PreambleMacros)
11111113
return;
1112-
for (const auto &MacroName : Preamble.Macros.Names)
1114+
for (const auto &MacroName : Preamble.Macros.Names) {
1115+
if (ITable.find(MacroName.getKey()) != ITable.end())
1116+
continue;
11131117
if (auto *II = PreambleIdentifiers->get(MacroName.getKey()))
11141118
if (II->isOutOfDate())
11151119
PreambleMacros->updateOutOfDateIdentifier(*II);
1120+
}
11161121
}
11171122

11181123
// Invokes Sema code completion on a file.

Diff for: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -3139,6 +3139,15 @@ TEST(CompletionTest, FunctionArgsExist) {
31393139
Kind(CompletionItemKind::Constructor))));
31403140
}
31413141

3142+
TEST(CompletionTest, NoCrashDueToMacroOrdering) {
3143+
EXPECT_THAT(completions(R"cpp(
3144+
#define ECHO(X) X
3145+
#define ECHO2(X) ECHO(X)
3146+
int finish_preamble = EC^HO(2);)cpp")
3147+
.Completions,
3148+
UnorderedElementsAre(Labeled("ECHO(X)"), Labeled("ECHO2(X)")));
3149+
}
3150+
31423151
} // namespace
31433152
} // namespace clangd
31443153
} // namespace clang

0 commit comments

Comments
 (0)