Help Clang find bottom of stacks for safety, use desired stack size

noteBottomOfStack:

Without this, checks against stack space within Clang don't work as
Clang doesn't know where the stack begins.

Needed per-thread, as early as possible.
(on threads using Clang)

Using Clang's desired stack size:

Additionally increase stack size of pthreads to Clang's desired size.

This is presently 8MB, and is used by Clang's stack management
mechanisms to check* if close to stack exhaustion when determining if
there's sufficient space (and warn or run on a new thread with more).
(see runWithSufficientStackSpace)

The constant is available in LLVM 7 onwards.

* (abs(cur - bottom) > DesiredStackSize - threshold)
This commit is contained in:
Will Dietz 2022-03-31 12:37:52 -05:00
parent 790daca4b2
commit 63c8800100
2 changed files with 24 additions and 3 deletions

View File

@ -8,6 +8,7 @@
#include "test.hh" #include "test.hh"
#include "working_files.hh" #include "working_files.hh"
#include <clang/Basic/Stack.h>
#include <clang/Basic/Version.h> #include <clang/Basic/Version.h>
#include <llvm/Support/CommandLine.h> #include <llvm/Support/CommandLine.h>
#include <llvm/Support/CrashRecoveryContext.h> #include <llvm/Support/CrashRecoveryContext.h>
@ -78,8 +79,12 @@ int main(int argc, char **argv) {
pipeline::init(); pipeline::init();
const char *env = getenv("CCLS_CRASH_RECOVERY"); const char *env = getenv("CCLS_CRASH_RECOVERY");
if (!env || strcmp(env, "0") != 0) if (!env || strcmp(env, "0") != 0) {
CrashRecoveryContext::Enable(); CrashRecoveryContext::Enable();
#if LLVM_VERSION_MAJOR >= 10 // rL369940
clang::noteBottomOfStack(); // per-thread, needed to avoid stack exhaustion
#endif
}
bool language_server = true; bool language_server = true;

View File

@ -27,6 +27,8 @@
#include <malloc.h> #include <malloc.h>
#endif #endif
#include <clang/Basic/Stack.h>
#include <llvm/ADT/SmallString.h> #include <llvm/ADT/SmallString.h>
#include <llvm/Support/Path.h> #include <llvm/Support/Path.h>
@ -61,18 +63,32 @@ void traceMe() {
raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP); raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP);
} }
struct ThreadInfo {
void *(*fn)(void *);
void *arg;
};
void *threadWrapper(void *arg) {
ThreadInfo ti = *(ThreadInfo *)arg;
delete (ThreadInfo *)arg;
#if LLVM_VERSION_MAJOR >= 10 // rL369940
clang::noteBottomOfStack(); // per-thread, needed to avoid stack exhaustion
#endif
return ti.fn(ti.arg);
}
void spawnThread(void *(*fn)(void *), void *arg) { void spawnThread(void *(*fn)(void *), void *arg) {
pthread_t thd; pthread_t thd;
pthread_attr_t attr; pthread_attr_t attr;
struct rlimit rlim; struct rlimit rlim;
size_t stack_size = 4 * 1024 * 1024; size_t stack_size = clang::DesiredStackSize;
if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur != RLIM_INFINITY) if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur != RLIM_INFINITY)
stack_size = rlim.rlim_cur; stack_size = rlim.rlim_cur;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, stack_size); pthread_attr_setstacksize(&attr, stack_size);
pipeline::threadEnter(); pipeline::threadEnter();
pthread_create(&thd, &attr, fn, arg); pthread_create(&thd, &attr, threadWrapper, new ThreadInfo{fn, arg});
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
} }
} // namespace ccls } // namespace ccls