[clang-tools-extra] [clangd] Fix SIGSEGV crash when receiving a textDocument/didOpen request with the URI pointing to a directory (PR #177834)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 31 07:28:28 PST 2026
https://github.com/dhr412 updated https://github.com/llvm/llvm-project/pull/177834
>From 1422d023b254999b33bee9ca6667bb1a3166a131 Mon Sep 17 00:00:00 2001
From: Dhruv <dhruv.baweja4 at gmail.com>
Date: Sun, 25 Jan 2026 10:58:24 +0530
Subject: [PATCH 1/3] [clangd] Handle directory URIs in didOpen and
documentSymbol
---
clang-tools-extra/clangd/ClangdLSPServer.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 761b07eceec83..58b130d185a4e 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -33,6 +33,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/SHA1.h"
@@ -730,6 +731,9 @@ void ClangdLSPServer::onSync(const NoParams &, Callback<std::nullptr_t> Reply) {
void ClangdLSPServer::onDocumentDidOpen(
const DidOpenTextDocumentParams &Params) {
PathRef File = Params.textDocument.uri.file();
+ if (llvm::sys::fs::is_directory(File)) {
+ return;
+ }
const std::string &Contents = Params.textDocument.text;
@@ -1027,6 +1031,10 @@ flattenSymbolHierarchy(llvm::ArrayRef<DocumentSymbol> Symbols,
void ClangdLSPServer::onDocumentSymbol(const DocumentSymbolParams &Params,
Callback<llvm::json::Value> Reply) {
URIForFile FileURI = Params.textDocument.uri;
+ if (llvm::sys::fs::is_directory(FileURI.file())) {
+ return Reply(llvm::make_error<LSPError>("URI is a directory",
+ ErrorCode::InvalidParams));
+ }
Server->documentSymbols(
Params.textDocument.uri.file(),
[this, FileURI, Reply = std::move(Reply)](
>From 5fa8dbdd6fc3b246b9d6bab03c8d3531443be6f6 Mon Sep 17 00:00:00 2001
From: Dhruv <dhruv.baweja4 at gmail.com>
Date: Sun, 25 Jan 2026 21:50:34 +0530
Subject: [PATCH 2/3] Update formatting to match coding standards
---
clang-tools-extra/clangd/ClangdLSPServer.cpp | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 58b130d185a4e..6f70ec3690ebd 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -731,9 +731,8 @@ void ClangdLSPServer::onSync(const NoParams &, Callback<std::nullptr_t> Reply) {
void ClangdLSPServer::onDocumentDidOpen(
const DidOpenTextDocumentParams &Params) {
PathRef File = Params.textDocument.uri.file();
- if (llvm::sys::fs::is_directory(File)) {
+ if (llvm::sys::fs::is_directory(File))
return;
- }
const std::string &Contents = Params.textDocument.text;
@@ -1031,10 +1030,9 @@ flattenSymbolHierarchy(llvm::ArrayRef<DocumentSymbol> Symbols,
void ClangdLSPServer::onDocumentSymbol(const DocumentSymbolParams &Params,
Callback<llvm::json::Value> Reply) {
URIForFile FileURI = Params.textDocument.uri;
- if (llvm::sys::fs::is_directory(FileURI.file())) {
+ if (llvm::sys::fs::is_directory(FileURI.file()))
return Reply(llvm::make_error<LSPError>("URI is a directory",
ErrorCode::InvalidParams));
- }
Server->documentSymbols(
Params.textDocument.uri.file(),
[this, FileURI, Reply = std::move(Reply)](
>From d5b709977be0e8ea5fb6e45ab19d065890a5f31c Mon Sep 17 00:00:00 2001
From: Dhruv <dhruv.baweja4 at gmail.com>
Date: Sat, 31 Jan 2026 20:58:11 +0530
Subject: [PATCH 3/3] Add err logging & lit test
---
clang-tools-extra/clangd/ClangdLSPServer.cpp | 7 ++--
.../clangd/test/directory-uri.test | 42 +++++++++++++++++++
2 files changed, 45 insertions(+), 4 deletions(-)
create mode 100644 clang-tools-extra/clangd/test/directory-uri.test
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 6f70ec3690ebd..5f95c3580f4ab 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -731,8 +731,10 @@ void ClangdLSPServer::onSync(const NoParams &, Callback<std::nullptr_t> Reply) {
void ClangdLSPServer::onDocumentDidOpen(
const DidOpenTextDocumentParams &Params) {
PathRef File = Params.textDocument.uri.file();
- if (llvm::sys::fs::is_directory(File))
+ if (llvm::sys::fs::is_directory(File)) {
+ elog("Ignoring didOpen for directory: {0}", File);
return;
+ }
const std::string &Contents = Params.textDocument.text;
@@ -1030,9 +1032,6 @@ flattenSymbolHierarchy(llvm::ArrayRef<DocumentSymbol> Symbols,
void ClangdLSPServer::onDocumentSymbol(const DocumentSymbolParams &Params,
Callback<llvm::json::Value> Reply) {
URIForFile FileURI = Params.textDocument.uri;
- if (llvm::sys::fs::is_directory(FileURI.file()))
- return Reply(llvm::make_error<LSPError>("URI is a directory",
- ErrorCode::InvalidParams));
Server->documentSymbols(
Params.textDocument.uri.file(),
[this, FileURI, Reply = std::move(Reply)](
diff --git a/clang-tools-extra/clangd/test/directory-uri.test b/clang-tools-extra/clangd/test/directory-uri.test
new file mode 100644
index 0000000000000..27b27a1f27d78
--- /dev/null
+++ b/clang-tools-extra/clangd/test/directory-uri.test
@@ -0,0 +1,42 @@
+# RUN: not --crash clangd -lit-test < %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+# RUN: not --crash clangd -lit-test -sync=0 < %s 2> %t.async.err
+# RUN: FileCheck %s < %t.async.err
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{
+ "uri":"file:///",
+ "languageId":"c",
+ "version":1,
+ "text":""
+}}}
+# CHECK: I[{{.*}}] Ignoring didOpen for directory: /
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{
+ "uri":"file:///tmp",
+ "languageId":"cpp",
+ "version":1,
+ "text":"int main() {}"
+}}}
+# CHECK: I[{{.*}}] Ignoring didOpen for directory: /tmp
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/documentSymbol","params":{"textDocument":{"uri":"file:///"}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602,
+# CHECK-NEXT: "message": "URI is a directory"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0"
+---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/documentSymbol","params":{"textDocument":{"uri":"file:///tmp"}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602,
+# CHECK-NEXT: "message": "URI is a directory"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 2,
+# CHECK-NEXT: "jsonrpc": "2.0"
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
More information about the cfe-commits
mailing list