r284271 - [linux] When pre-reserving stack pages to work around broken address space

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 14 12:51:36 PDT 2016


Author: rsmith
Date: Fri Oct 14 14:51:36 2016
New Revision: 284271

URL: http://llvm.org/viewvc/llvm-project?rev=284271&view=rev
Log:
[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.

Modified:
    cfe/trunk/tools/driver/cc1_main.cpp

Modified: cfe/trunk/tools/driver/cc1_main.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/cc1_main.cpp?rev=284271&r1=284270&r2=284271&view=diff
==============================================================================
--- cfe/trunk/tools/driver/cc1_main.cpp (original)
+++ cfe/trunk/tools/driver/cc1_main.cpp Fri Oct 14 14:51:36 2016
@@ -80,20 +80,48 @@ void initializePollyPasses(llvm::PassReg
 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() {}




More information about the cfe-commits mailing list