From c9ac524df4a96642035a43b711520e373b339936 Mon Sep 17 00:00:00 2001 From: ykiko Date: Thu, 23 Apr 2026 03:29:44 +0800 Subject: [PATCH 1/2] fix: prevent worker crashes from null ASTConsumer, invalid FileID, and missing PCH cache dir Three pre-existing bugs cause worker processes to crash (SEGV/SIGABRT), which becomes a reliability issue when combined with the respawn mechanism on low-core CI machines. - compilation.cpp: Check for null before passing WrapperFrontendAction's ASTConsumer to MultiplexConsumer (prevents SEGV in stateless workers during PCH builds when CreateASTConsumer fails) - compilation_unit.cpp: Return empty StringRef on invalid FileID instead of asserting (prevents SIGABRT in stateful workers when compilation produces an AST with no valid main file, e.g. synthesized default commands without system headers) - compiler.cpp: Create PCH cache directory before sending build request to stateless worker (prevents "No such file or directory" when load_workspace didn't run due to missing compile_commands.json - master_server: Make load_workspace a plain synchronous function since it contains no async operations EOF ) Made-with: Cursor --- src/compile/compilation.cpp | 7 ++++--- src/compile/compilation_unit.cpp | 3 ++- src/server/compiler.cpp | 16 ++++++++++++++++ src/server/master_server.cpp | 8 ++++---- src/server/master_server.h | 2 +- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/compile/compilation.cpp b/src/compile/compilation.cpp index bce235f30..ffc5bf386 100644 --- a/src/compile/compilation.cpp +++ b/src/compile/compilation.cpp @@ -219,9 +219,10 @@ class ProxyAction final : public clang::WrapperFrontendAction { auto CreateASTConsumer(clang::CompilerInstance& instance, llvm::StringRef file) -> std::unique_ptr final { - return std::make_unique( - WrapperFrontendAction::CreateASTConsumer(instance, file), - unit); + auto consumer = WrapperFrontendAction::CreateASTConsumer(instance, file); + if(!consumer) + return nullptr; + return std::make_unique(std::move(consumer), unit); } /// Make this public. diff --git a/src/compile/compilation_unit.cpp b/src/compile/compilation_unit.cpp index c82704f42..03d56576e 100644 --- a/src/compile/compilation_unit.cpp +++ b/src/compile/compilation_unit.cpp @@ -81,7 +81,8 @@ auto CompilationUnitRef::file_offset(clang::SourceLocation location) -> std::uin } auto CompilationUnitRef::file_path(clang::FileID fid) -> llvm::StringRef { - assert(fid.isValid() && "Invalid fid"); + if(!fid.isValid()) + return {}; if(auto it = self->path_cache.find(fid); it != self->path_cache.end()) { return it->second; } diff --git a/src/server/compiler.cpp b/src/server/compiler.cpp index 349dfeb8d..0686049b4 100644 --- a/src/server/compiler.cpp +++ b/src/server/compiler.cpp @@ -490,6 +490,22 @@ kota::task Compiler::ensure_pch(Session& session, auto completion = std::make_shared(); workspace.pch_cache[path_id].building = completion; + if(workspace.config.project.cache_dir.empty()) { + LOG_WARN("PCH build skipped: cache_dir is not configured"); + workspace.pch_cache[path_id].building.reset(); + completion->set(); + co_return false; + } + + // Ensure the PCH cache directory exists. + auto pch_dir = path::join(workspace.config.project.cache_dir, "cache", "pch"); + if(auto ec = llvm::sys::fs::create_directories(pch_dir)) { + LOG_WARN("Cannot create PCH cache dir {}: {}", pch_dir, ec.message()); + workspace.pch_cache[path_id].building.reset(); + completion->set(); + co_return false; + } + // Build a new PCH via stateless worker. worker::BuildParams bp; bp.kind = worker::BuildKind::BuildPCH; diff --git a/src/server/master_server.cpp b/src/server/master_server.cpp index 790b258f0..f5a6bf853 100644 --- a/src/server/master_server.cpp +++ b/src/server/master_server.cpp @@ -56,9 +56,9 @@ MasterServer::MasterServer(kota::event_loop& loop, MasterServer::~MasterServer() = default; -kota::task<> MasterServer::load_workspace() { +void MasterServer::load_workspace() { if(workspace_root.empty()) - co_return; + return; auto& cfg = workspace.config.project; @@ -125,7 +125,7 @@ kota::task<> MasterServer::load_workspace() { if(cdb_path.empty()) { LOG_WARN("No compile_commands.json found in workspace {}", workspace_root); - co_return; + return; } auto count = workspace.cdb.load(cdb_path); @@ -331,7 +331,7 @@ void MasterServer::register_handlers() { indexer.schedule(); }; - loop.schedule(load_workspace()); + load_workspace(); }); peer.on_request( diff --git a/src/server/master_server.h b/src/server/master_server.h index 250be8d94..7a892f75a 100644 --- a/src/server/master_server.h +++ b/src/server/master_server.h @@ -73,7 +73,7 @@ class MasterServer { std::string session_log_dir; std::string init_options_json; ///< Raw JSON from initializationOptions, consumed once. - kota::task<> load_workspace(); + void load_workspace(); using RawResult = kota::task; }; From 80090986bf2c5cccad06995976b041b496047d6e Mon Sep 17 00:00:00 2001 From: ykiko Date: Thu, 23 Apr 2026 03:40:55 +0800 Subject: [PATCH 2/2] refactor: update kota/codec includes for new kotatsu header layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kotatsu moved all codec headers into subdirectories; top-level files like codec/raw_value.h and codec/toml.h no longer exist. - codec/raw_value.h → removed (re-exported by json/json.h and bincode/bincode.h) - codec/toml.h → codec/toml/toml.h - codec/json/serializer.h → codec/json/json.h (use umbrella header) Made-with: Cursor --- benchmarks/scan_benchmark.cpp | 2 +- src/server/compiler.h | 2 +- src/server/config.cpp | 2 +- src/server/master_server.h | 2 +- src/server/protocol.h | 2 +- src/server/worker_common.h | 3 +-- tests/unit/server/config_tests.cpp | 2 +- tests/unit/server/stateful_worker_tests.cpp | 2 +- tests/unit/server/stateless_worker_tests.cpp | 1 - 9 files changed, 8 insertions(+), 10 deletions(-) diff --git a/benchmarks/scan_benchmark.cpp b/benchmarks/scan_benchmark.cpp index d44b31cb2..2c30861ec 100644 --- a/benchmarks/scan_benchmark.cpp +++ b/benchmarks/scan_benchmark.cpp @@ -26,7 +26,7 @@ #include "support/path_pool.h" #include "syntax/dependency_graph.h" -#include "kota/codec/json/serializer.h" +#include "kota/codec/json/json.h" #include "kota/deco/deco.h" #include "llvm/Support/FileSystem.h" diff --git a/src/server/compiler.h b/src/server/compiler.h index 2ee5bf33e..c0c7b71d5 100644 --- a/src/server/compiler.h +++ b/src/server/compiler.h @@ -14,7 +14,7 @@ #include "syntax/completion.h" #include "kota/async/async.h" -#include "kota/codec/raw_value.h" +#include "kota/codec/json/json.h" #include "kota/ipc/codec/json.h" #include "kota/ipc/lsp/protocol.h" #include "kota/ipc/peer.h" diff --git a/src/server/config.cpp b/src/server/config.cpp index 00ee41b50..a2d8087ca 100644 --- a/src/server/config.cpp +++ b/src/server/config.cpp @@ -7,7 +7,7 @@ #include "support/logging.h" #include "kota/codec/json/json.h" -#include "kota/codec/toml.h" +#include "kota/codec/toml/toml.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" diff --git a/src/server/master_server.h b/src/server/master_server.h index 7a892f75a..94106fffa 100644 --- a/src/server/master_server.h +++ b/src/server/master_server.h @@ -12,7 +12,7 @@ #include "server/workspace.h" #include "kota/async/async.h" -#include "kota/codec/raw_value.h" +#include "kota/codec/json/json.h" #include "kota/ipc/peer.h" #include "llvm/ADT/DenseMap.h" diff --git a/src/server/protocol.h b/src/server/protocol.h index 641c03440..1a2774c78 100644 --- a/src/server/protocol.h +++ b/src/server/protocol.h @@ -9,7 +9,7 @@ #include "syntax/token.h" -#include "kota/codec/raw_value.h" +#include "kota/codec/json/json.h" #include "kota/ipc/lsp/protocol.h" #include "kota/ipc/protocol.h" diff --git a/src/server/worker_common.h b/src/server/worker_common.h index fb73e40df..45bfa3a46 100644 --- a/src/server/worker_common.h +++ b/src/server/worker_common.h @@ -8,8 +8,7 @@ #include "compile/compilation.h" -#include "kota/codec/json/serializer.h" -#include "kota/codec/raw_value.h" +#include "kota/codec/json/json.h" #include "kota/ipc/codec/json.h" namespace clice { diff --git a/tests/unit/server/config_tests.cpp b/tests/unit/server/config_tests.cpp index f29f81017..1cfb550a0 100644 --- a/tests/unit/server/config_tests.cpp +++ b/tests/unit/server/config_tests.cpp @@ -6,7 +6,7 @@ #include "support/filesystem.h" #include "kota/codec/json/json.h" -#include "kota/codec/toml.h" +#include "kota/codec/toml/toml.h" namespace clice::testing { diff --git a/tests/unit/server/stateful_worker_tests.cpp b/tests/unit/server/stateful_worker_tests.cpp index 8ef426088..d16f6c622 100644 --- a/tests/unit/server/stateful_worker_tests.cpp +++ b/tests/unit/server/stateful_worker_tests.cpp @@ -5,7 +5,7 @@ #include "server/protocol.h" #include "server/worker_test_helpers.h" -#include "kota/codec/raw_value.h" +#include "kota/codec/json/json.h" namespace clice::testing { diff --git a/tests/unit/server/stateless_worker_tests.cpp b/tests/unit/server/stateless_worker_tests.cpp index e79a6b795..0cc8b4848 100644 --- a/tests/unit/server/stateless_worker_tests.cpp +++ b/tests/unit/server/stateless_worker_tests.cpp @@ -6,7 +6,6 @@ #include "server/worker_test_helpers.h" #include "kota/codec/bincode/bincode.h" -#include "kota/codec/raw_value.h" namespace clice::testing {