[clang-tools-extra] [clangd] fix crash in include cleaner (PR #99514)

via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 18 08:28:08 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tools-extra

Author: Yuxuan Shui (yshui)

<details>
<summary>Changes</summary>

Unsure if this is the correct fix. But let me explain what I know so far about this problem:

1. Include cleaner goes over macro refs, and calculates their source locations:
    https://github.com/llvm/llvm-project/blob/676efd0ffb717215c752f200fe14163732290dcc/clang-tools-extra/clangd/IncludeCleaner.cpp#L303-L305
2. It assumes the macro ref is in the main file. I think the intention is that `ParsedAST::Macros` only contains macro usages in the main file.
3. `ParsedAST::Macros` is filled in by `CollectMainFileMacros`:
    https://github.com/llvm/llvm-project/blob/676efd0ffb717215c752f200fe14163732290dcc/clang-tools-extra/clangd/CollectMacros.cpp#L27-L43
4. `CollectMainFileMacros` checks if the macro usage is in main file with `if (InMainFile)`, and `InMainFile` is updated in `CollectMainFileMacros::FileChange`.
5. I think the intention of `PPCallbacks::FileChange` is 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 observed `CollectMainFileMacros::add` being calling with source locations that are clearly not in the same file as reported by the most recent `FileChange`.

The consequence of that is that `CollectMainFileMacros` will 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 triggers a assertion failure at:

https://github.com/llvm/llvm-project/blob/497ea1d84951626dea5bf644fef2d99e145e21ac/clang/lib/Tooling/Syntax/Tokens.cpp#L382

* * *

What I did here is instead of using `InMainFile`/`PPCallbacks::FileChange` to make sure the macro is in the main file, I check the `FileID` directly

---
Full diff: https://github.com/llvm/llvm-project/pull/99514.diff


1 Files Affected:

- (modified) clang-tools-extra/clangd/CollectMacros.cpp (+7-7) 


``````````diff
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());

``````````

</details>


https://github.com/llvm/llvm-project/pull/99514


More information about the cfe-commits mailing list