summaryrefslogtreecommitdiffstats
path: root/tools/driver
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-10-14 19:51:36 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-10-14 19:51:36 +0000
commita7f432ba8fe081688060425ab1f0c5423ec9a587 (patch)
tree81a0edd19a51f2d9dfddaaf882424fa343671f4a /tools/driver
parentbab2991fda9242a15e142c13be156e1e6b984b09 (diff)
[linux] When pre-reserving stack pages to work around broken address space
layout for PIE binaries, ask the OS how much stack space is already in use to avoid stack overflow if we are run with more than 512K of combined command line arguments + environment variables. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@284271 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/driver')
-rw-r--r--tools/driver/cc1_main.cpp42
1 files changed, 35 insertions, 7 deletions
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 45d44a015e..0d54278ee8 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -80,20 +80,48 @@ void initializePollyPasses(llvm::PassRegistry &Registry);
static const int kSufficientStack = 8 << 20;
#if defined(__linux__) && defined(__PIE__)
+static size_t getCurrentStackAllocation() {
+ // If we can't compute the current stack usage, allow for 512K of command
+ // line arguments and environment.
+ size_t Usage = 512 * 1024;
+ if (FILE *StatFile = fopen("/proc/self/stat", "r")) {
+ // We assume that the stack extends from its current address to the end of
+ // the environment space. In reality, there is another string literal (the
+ // program name) after the environment, but this is close enough (we only
+ // need to be within 100K or so).
+ unsigned long StackPtr, EnvEnd;
+ if (fscanf(StatFile,
+ "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu "
+ "%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu "
+ "%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d "
+ "%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d",
+ &StackPtr, &EnvEnd) == 2) {
+ Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd;
+ }
+ fclose(StatFile);
+ }
+ return Usage;
+}
+
+#include <alloca.h>
+
LLVM_ATTRIBUTE_NOINLINE
-static void ensureStackAddressSpace() {
+static void ensureStackAddressSpace(int ExtraChunks = 0) {
// 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];
+ // pages allocated before we start running.
+ size_t Curr = getCurrentStackAllocation();
+ const int kTargetStack = kSufficientStack - 256 * 1024;
+ if (Curr < kTargetStack) {
+ volatile char *volatile Alloc =
+ static_cast<volatile char *>(alloca(kTargetStack - Curr));
+ Alloc[0] = 0;
+ Alloc[kTargetStack - Curr - 1] = 0;
+ }
}
#else
static void ensureStackAddressSpace() {}