- Notifications
You must be signed in to change notification settings - Fork 15.3k
[clangd] fix crash in include cleaner #99514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| @llvm/pr-subscribers-clangd @llvm/pr-subscribers-clang-tools-extra Author: Yuxuan Shui (yshui) ChangesUnsure if this is the correct fix. But let me explain what I know so far about this problem:
Above is what I am sure about, after that I am not quite sure what's happening. I think macro expansions ( The consequence of that is that
What I did here is instead of using Full diff: https://github.com/llvm/llvm-project/pull/99514.diff 1 Files Affected:
diff --git a/clang-tools-extra/clangd/CollectMacros.cpp b/clang-tools-extra/clangd/CollectMacros.cpp index c5ba8d903ba48..bda5616447193 100644 --- a/clang-tools-extra/clangd/CollectMacros.cpp +++ b/clang-tools-extra/clangd/CollectMacros.cpp @@ -26,11 +26,12 @@ Range MacroOccurrence::toRange(const SourceManager &SM) const { void CollectMainFileMacros::add(const Token &MacroNameTok, const MacroInfo *MI, bool IsDefinition, bool InIfCondition) { - if (!InMainFile) - return; auto Loc = MacroNameTok.getLocation(); if (Loc.isInvalid() || Loc.isMacroID()) return; + auto FID = SM.getFileID(Loc); + if (FID != SM.getMainFileID()) + return; auto Name = MacroNameTok.getIdentifierInfo()->getName(); Out.Names.insert(Name); @@ -42,10 +43,8 @@ void CollectMainFileMacros::add(const Token &MacroNameTok, const MacroInfo *MI, Out.UnknownMacros.push_back({Start, End, IsDefinition, InIfCondition}); } -void CollectMainFileMacros::FileChanged(SourceLocation Loc, FileChangeReason, - SrcMgr::CharacteristicKind, FileID) { - InMainFile = isInsideMainFile(Loc, SM); -} +void CollectMainFileMacros::FileChanged(SourceLocation, FileChangeReason, + SrcMgr::CharacteristicKind, FileID) {} void CollectMainFileMacros::MacroExpands(const Token &MacroName, const MacroDefinition &MD, @@ -93,7 +92,8 @@ void CollectMainFileMacros::Defined(const Token &MacroName, void CollectMainFileMacros::SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) { - if (!InMainFile) + auto FID = SM.getFileID(R.getBegin()); + if (FID != SM.getMainFileID()) return; Position Begin = sourceLocToPosition(SM, R.getBegin()); Position End = sourceLocToPosition(SM, R.getEnd()); |
| I can provide a repro if anyone is interested |
| Looks like I definitely don't understand what's going on. Instead let me try a more conservative fix. This should preserve what the current code is doing and just fix the assertion failure. |
| ✅ With the latest revision this PR passed the C/C++ code formatter. |
| Is there a bug report this is fixing? Or a test case? |
| Good question. I will try to add one once I figure out how this test system works |
Could you say more about what problem you ran into with the first fix approach? |
| @HighCommander4 It's been a while. I think I was trying to ignore everything but the main file in CollectMacros, but the naive approach i used wasn't working |
HighCommander4 left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having debugged the failing scenario a bit (see this comment), my sense is that we do not want to accept MacroRefs entries which are not in the main file; instead, I have a proposal for an alternative solution at the end of that comment.
Let me know if you're interested in implementing it, otherwise I can do it.
| @HighCommander4 thanks for looking into this! I think this can be closed, right? |
Unsure if this is the correct fix. But let me explain what I know so far about this problem:
llvm-project/clang-tools-extra/clangd/IncludeCleaner.cpp
Lines 303 to 305 in 676efd0
ParsedAST::Macrosis meant to only contain macro usages in the main file.ParsedAST::Macrosis filled in byCollectMainFileMacros:llvm-project/clang-tools-extra/clangd/CollectMacros.cpp
Lines 27 to 43 in 676efd0
CollectMainFileMacroschecks if a macro usage is in main file withif (InMainFile), which is updated inCollectMainFileMacros::FileChange.PPCallbacks::FileChangeis that it is called whenever the lexer moves to a new file.Above is what I am sure about, after that I am not quite sure what's happening.
I think macro expansions (
HandleIdentifier -> HandleMacroExpansion) are done out of the normal file change logic? Because I observedCollectMainFileMacros::addbeing called with source locations that are clearly not in the same file as reported by the most recentFileChange.The consequence of that is that
CollectMainFileMacroswill get offsets related to one file, and those offsets will later be combined with another file (the main file) into a source location in the include cleaner. Those source locations will then be used to get a spelling, which at best will be wrong, and at worst will trigger an assertion failure at:llvm-project/clang/lib/Tooling/Syntax/Tokens.cpp
Line 382 in 497ea1d
What I did here is instead of using
InMainFile/PPCallbacks::FileChangeto make sure the macro is in the main file, I check theFileIDdirectly