From 194b6a3b1b1a99cc3c12c466a04320f271ebd8aa Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 17 Aug 2016 01:05:07 +0000 Subject: [PATCH] If possible, set the stack rlimit to at least 8MiB on cc1 startup, and work around a Linux kernel bug where the actual amount of available stack may be a *lot* lower than the rlimit. GCC also sets a higher stack rlimit on startup, but it goes all the way to 64MiB. We can increase this limit if it proves necessary. The kernel bug is as follows: Linux kernels prior to version 4.1 may choose to map the process's heap as little as 128MiB before the process's stack for a PIE binary, even in a 64-bit virtual address space. This means that allocating more than 128MiB before you reach the process's stack high water mark can lead to crashes, even if you don't recurse particularly deeply. We work around the kernel bug by touching a page deep within the stack (after ensuring that we know how big it is), to preallocate virtual address space for the stack so that the kernel doesn't allow the brk() area to wander into it, when building clang as a Linux PIE binary. llvm-svn: 278882 --- clang/tools/driver/cc1_main.cpp | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index d78a31e..b8b6ebe 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -25,9 +25,11 @@ #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Config/config.h" #include "llvm/LinkAllPasses.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Signals.h" @@ -35,6 +37,9 @@ #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include +#if HAVE_SYS_RESOURCE_H +#include +#endif using namespace clang; using namespace llvm::opt; @@ -64,7 +69,67 @@ void initializePollyPasses(llvm::PassRegistry &Registry); } #endif +#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT +// The amount of stack we think is "sufficient". If less than this much is +// available, we may be unable to reach our template instantiation depth +// limit and other similar limits. +// FIXME: Unify this with the stack we request when spawning a thread to build +// a module. +static const int kSufficientStack = 8 << 20; + +#if defined(__linux__) && defined(__PIE__) +LLVM_ATTRIBUTE_NOINLINE +static void ensureStackAddressSpace() { + // Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary + // relatively close to the stack (they are only guaranteed to be 128MiB + // apart). This results in crashes if we happen to heap-allocate more than + // 128MiB before we reach our stack high-water mark. + // + // To avoid these crashes, ensure that we have sufficient virtual memory + // pages allocated before we start running by touching an early page. (We + // allow 512KiB for kernel/libc-provided data such as command-line arguments + // and environment variables, and for main and cc1_main) + volatile char ReservedStack[kSufficientStack - 512 * 1024]; + volatile int N = 0; + (void)+ReservedStack[N]; +} +#else +static void ensureStackAddressSpace() {} +#endif + +/// Attempt to ensure that we have at least 8MiB of usable stack space. +static void ensureSufficientStack() { + struct rlimit rlim; + if (getrlimit(RLIMIT_STACK, &rlim) != 0) + return; + + // Increase the soft stack limit to our desired level, if necessary and + // possible. + if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kSufficientStack) { + // Try to allocate sufficient stack. + if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max >= kSufficientStack) + rlim.rlim_cur = kSufficientStack; + else if (rlim.rlim_cur == rlim.rlim_max) + return; + else + rlim.rlim_cur = rlim.rlim_max; + + if (setrlimit(RLIMIT_STACK, &rlim) != 0 || + rlim.rlim_cur != kSufficientStack) + return; + } + + // We should now have a stack of size at least kSufficientStack. Ensure + // that we can actually use that much, if necessary. + ensureStackAddressSpace(); +} +#else +static void ensureSufficientStack() { +#endif + int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { + ensureSufficientStack(); + std::unique_ptr Clang(new CompilerInstance()); IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); -- 2.7.4