diff --git a/clang-tools-extra/clangd/Threading.cpp b/clang-tools-extra/clangd/Threading.cpp --- a/clang-tools-extra/clangd/Threading.cpp +++ b/clang-tools-extra/clangd/Threading.cpp @@ -1,5 +1,6 @@ #include "Threading.h" #include "Trace.h" +#include "clang/Basic/Stack.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Threading.h" @@ -86,16 +87,16 @@ } }); - std::thread( - [](std::string Name, decltype(Action) Action, decltype(CleanupTask)) { - llvm::set_thread_name(Name); - Action(); - // Make sure function stored by Action is destroyed before CleanupTask - // is run. - Action = nullptr; - }, - Name.str(), std::move(Action), std::move(CleanupTask)) - .detach(); + auto Task = [Name = Name.str(), Action = std::move(Action), + Cleanup = std::move(CleanupTask)]() mutable { + llvm::set_thread_name(Name); + Action(); + // Make sure function stored by ThreadFunc is destroyed before Cleanup runs. + Action = nullptr; + }; + + // Ensure our worker threads have big enough stacks to run clang. + llvm::llvm_execute_on_thread_async(std::move(Task), clang::DesiredStackSize); } Deadline timeoutSeconds(llvm::Optional Seconds) { diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -1065,6 +1065,27 @@ Field(&CodeCompletion::Scope, "ns::")))); } +TEST_F(ClangdVFSTest, TestStackOverflow) { + MockFSProvider FS; + ErrorCheckingCallbacks DiagConsumer; + MockCompilationDatabase CDB; + ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer); + + const char *SourceContents = R"cpp( + constexpr int foo() { return foo(); } + static_assert(foo()); + )cpp"; + + auto FooCpp = testPath("foo.cpp"); + FS.Files[FooCpp] = SourceContents; + + Server.addDocument(FooCpp, SourceContents); + ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics"; + // check that we got a constexpr depth error, and not crashed by stack + // overflow + EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags()); +} + } // namespace } // namespace clangd } // namespace clang