summaryrefslogtreecommitdiffstats
path: root/tools/driver
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-08-17 01:05:07 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-08-17 01:05:07 +0000
commitccf83ec184737bf7a2090ab8ac010e33f46439c6 (patch)
tree654bac06b834ac01157b258718f0f47eb1d8d90a /tools/driver
parenteb1960e75654998eb9ade318fbcabaae4fa0064d (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@278882 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/driver')
-rw-r--r--tools/driver/cc1_main.cpp65
1 files changed, 65 insertions, 0 deletions
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index d78a31e67a..b8b6ebe03d 100644
--- a/tools/driver/cc1_main.cpp
+++ b/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 <cstdio>
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#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<const char *> Argv, const char *Argv0, void *MainAddr) {
+ ensureSufficientStack();
+
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());