diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -34,6 +34,7 @@ #include "support/MemoryTree.h" #include "support/ThreadsafeFS.h" #include "support/Trace.h" +#include "clang/Basic/Stack.h" #include "clang/Format/Format.h" #include "clang/Lex/Preprocessor.h" #include "clang/Tooling/CompilationDatabase.h" @@ -52,8 +53,8 @@ #include #include #include -#include #include +#include namespace clang { namespace clangd { @@ -112,6 +113,7 @@ FIndex(FIndex), // shared_ptr extends lifetime Stdlib(Stdlib)]() mutable { + clang::noteBottomOfStack(); IndexFileIn IF; IF.Symbols = indexStandardLibrary(std::move(CI), Loc, *TFS); if (Stdlib->isBest(LO)) diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -63,6 +63,7 @@ #include "support/ThreadCrashReporter.h" #include "support/Threading.h" #include "support/Trace.h" +#include "clang/Basic/Stack.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/FunctionExtras.h" @@ -464,6 +465,10 @@ } void run() { + // We mark the current as the stack bottom so that clang running on this + // thread can notice the stack usage and prevent stack overflow with best + // efforts. Same applies to other calls thoughout clangd. + clang::noteBottomOfStack(); while (true) { std::optional Throttle; { @@ -1383,6 +1388,7 @@ } void ASTWorker::run() { + clang::noteBottomOfStack(); while (true) { { std::unique_lock Lock(Mutex); @@ -1777,6 +1783,7 @@ Ctx = Context::current().derive(FileBeingProcessed, std::string(File)), Action = std::move(Action), this]() mutable { + clang::noteBottomOfStack(); ThreadCrashReporter ScopedReporter([&Name, &Contents, &Command]() { llvm::errs() << "Signalled during preamble action: " << Name << "\n"; crashDumpCompileCommand(llvm::errs(), Command); diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp --- a/clang-tools-extra/clangd/index/Background.cpp +++ b/clang-tools-extra/clangd/index/Background.cpp @@ -30,6 +30,7 @@ #include "support/Trace.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Stack.h" #include "clang/Frontend/FrontendAction.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" @@ -108,6 +109,7 @@ for (unsigned I = 0; I < Opts.ThreadPoolSize; ++I) { ThreadPool.runAsync("background-worker-" + llvm::Twine(I + 1), [this, Ctx(Context::current().clone())]() mutable { + clang::noteBottomOfStack(); WithContext BGContext(std::move(Ctx)); Queue.work([&] { Rebuilder.idle(); }); }); diff --git a/clang-tools-extra/clangd/test/infinite-instantiation.test b/clang-tools-extra/clangd/test/infinite-instantiation.test new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/test/infinite-instantiation.test @@ -0,0 +1,13 @@ +// RUN: cp %s %t.cpp +// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s + +// CHECK: [template_recursion_depth_exceeded] + +template +constexpr int f(T... args) { + return f(0, args...); +} + +int main() { + auto i = f(); +} diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -29,6 +29,7 @@ #include "support/ThreadCrashReporter.h" #include "support/ThreadsafeFS.h" #include "support/Trace.h" +#include "clang/Basic/Stack.h" #include "clang/Format/Format.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -710,6 +711,9 @@ }; int clangdMain(int argc, char *argv[]) { + // Clang could run on the main thread. e.g., when the flag '-check' or '-sync' + // is enabled. + clang::noteBottomOfStack(); llvm::InitializeAllTargetInfos(); llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::sys::AddSignalHandler( diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/FileEntry.h" #include "clang/Basic/LangStandard.h" #include "clang/Basic/Sarif.h" +#include "clang/Basic/Stack.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -1155,6 +1156,10 @@ CompilerInstance &CI = getCompilerInstance(); if (!CI.hasPreprocessor()) return; + // This is a fallback: If the client forgets to invoke this, we mark the + // current stack as the bottom. Though not optimal, this could help prevent + // stack overflow during deep recursion. + clang::noteBottomOfStack(); // FIXME: Move the truncation aspect of this into Sema, we delayed this till // here so the source manager would be initialized.