[clang-tools-extra] a2f7352 - [clangd] Dont run raw-lexer for OOB source locations

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Thu May 25 00:43:13 PDT 2023


Author: Kadir Cetinkaya
Date: 2023-05-25T09:38:04+02:00
New Revision: a2f7352f3e809cb1b267e769d00ea84e4ef46bf0

URL: https://github.com/llvm/llvm-project/commit/a2f7352f3e809cb1b267e769d00ea84e4ef46bf0
DIFF: https://github.com/llvm/llvm-project/commit/a2f7352f3e809cb1b267e769d00ea84e4ef46bf0.diff

LOG: [clangd] Dont run raw-lexer for OOB source locations

We can get stale source locations from preamble, make sure we don't
access those locations without checking first.

Fixes https://github.com/clangd/clangd/issues/1636.

Differential Revision: https://reviews.llvm.org/D151321

Added: 
    

Modified: 
    clang-tools-extra/clangd/Diagnostics.cpp
    clang-tools-extra/clangd/unittests/PreambleTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp
index b708f9c3d3b03..4c5def3063f1e 100644
--- a/clang-tools-extra/clangd/Diagnostics.cpp
+++ b/clang-tools-extra/clangd/Diagnostics.cpp
@@ -96,7 +96,8 @@ bool locationInRange(SourceLocation L, CharSourceRange R,
 
 // Clang diags have a location (shown as ^) and 0 or more ranges (~~~~).
 // LSP needs a single range.
-Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
+std::optional<Range> diagnosticRange(const clang::Diagnostic &D,
+                                     const LangOptions &L) {
   auto &M = D.getSourceManager();
   auto PatchedRange = [&M](CharSourceRange &R) {
     R.setBegin(translatePreamblePatchLocation(R.getBegin(), M));
@@ -115,13 +116,18 @@ Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
     if (locationInRange(Loc, R, M))
       return halfOpenToRange(M, PatchedRange(R));
   }
+  // Source locations from stale preambles might become OOB.
+  // FIXME: These diagnostics might point to wrong locations even when they're
+  // not OOB.
+  auto [FID, Offset] = M.getDecomposedLoc(Loc);
+  if (Offset > M.getBufferData(FID).size())
+    return std::nullopt;
   // If the token at the location is not a comment, we use the token.
   // If we can't get the token at the location, fall back to using the location
   auto R = CharSourceRange::getCharRange(Loc);
   Token Tok;
-  if (!Lexer::getRawToken(Loc, Tok, M, L, true) && Tok.isNot(tok::comment)) {
+  if (!Lexer::getRawToken(Loc, Tok, M, L, true) && Tok.isNot(tok::comment))
     R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc());
-  }
   return halfOpenToRange(M, PatchedRange(R));
 }
 
@@ -697,7 +703,10 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
     SourceLocation PatchLoc =
         translatePreamblePatchLocation(Info.getLocation(), SM);
     D.InsideMainFile = isInsideMainFile(PatchLoc, SM);
-    D.Range = diagnosticRange(Info, *LangOpts);
+    if (auto DRange = diagnosticRange(Info, *LangOpts))
+      D.Range = *DRange;
+    else
+      D.Severity = DiagnosticsEngine::Ignored;
     auto FID = SM.getFileID(Info.getLocation());
     if (const auto FE = SM.getFileEntryRefForID(FID)) {
       D.File = FE->getName().str();

diff  --git a/clang-tools-extra/clangd/unittests/PreambleTests.cpp b/clang-tools-extra/clangd/unittests/PreambleTests.cpp
index 23ba0fc3e52fc..4f2cc3e0abe77 100644
--- a/clang-tools-extra/clangd/unittests/PreambleTests.cpp
+++ b/clang-tools-extra/clangd/unittests/PreambleTests.cpp
@@ -829,6 +829,37 @@ x>)");
     auto AST = createPatchedAST(Code.code(), NewCode.code());
     EXPECT_THAT(*AST->getDiagnostics(), IsEmpty());
   }
+  {
+    Annotations Code(R"(
+#ifndef FOO
+#define FOO
+void foo();
+#endif)");
+    // This code will emit a diagnostic for unterminated #ifndef (as stale
+    // preamble has the conditional but main file doesn't terminate it).
+    // We shouldn't emit any diagnotiscs (and shouldn't crash).
+    Annotations NewCode("");
+    auto AST = createPatchedAST(Code.code(), NewCode.code());
+    EXPECT_THAT(*AST->getDiagnostics(), IsEmpty());
+  }
+  {
+    Annotations Code(R"(
+#ifndef FOO
+#define FOO
+void foo();
+#endif)");
+    // This code will emit a diagnostic for unterminated #ifndef (as stale
+    // preamble has the conditional but main file doesn't terminate it).
+    // We shouldn't emit any diagnotiscs (and shouldn't crash).
+    // FIXME: Patch/ignore diagnostics in such cases.
+    Annotations NewCode(R"(
+i[[nt]] xyz;
+    )");
+    auto AST = createPatchedAST(Code.code(), NewCode.code());
+    EXPECT_THAT(
+        *AST->getDiagnostics(),
+        ElementsAre(Diag(NewCode.range(), "pp_unterminated_conditional")));
+  }
 }
 
 MATCHER_P2(Mark, Range, Text, "") {


        


More information about the cfe-commits mailing list