base: Set up a guard page for fiber stacks.
authorGabe Black <gabeblack@google.com>
Sat, 17 Nov 2018 01:07:42 +0000 (17:07 -0800)
committerGabe Black <gabeblack@google.com>
Sun, 18 Nov 2018 10:44:26 +0000 (10:44 +0000)
This will help detect stack overflow for fibers.

Change-Id: Iff2b102120ec351709e495291d6bead597f8d10c
Reviewed-on: https://gem5-review.googlesource.com/c/14395
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Maintainer: Gabe Black <gabeblack@google.com>

src/base/fiber.cc
src/base/fiber.hh

index eac1d9394cfe9ec38a4403c1183e72bf712ce3c0..af63216da207678a0abfebda46028b056785a8e4 100644 (file)
 #include <valgrind/valgrind.h>
 #endif
 
+#include <sys/mman.h>
+#include <unistd.h>
+
 #include <cerrno>
+#include <cstdio>
 #include <cstring>
 
 #include "base/logging.hh"
@@ -71,28 +75,41 @@ Fiber::entryTrampoline()
     startingFiber->start();
 }
 
-Fiber::Fiber(size_t stack_size) :
-    link(primaryFiber()),
-    stack(stack_size ? new uint8_t[stack_size] : nullptr),
-    stackSize(stack_size), started(false), _finished(false)
+Fiber::Fiber(size_t stack_size) : Fiber(primaryFiber(), stack_size)
+{}
+
+Fiber::Fiber(Fiber *link, size_t stack_size) :
+    link(link), stack(nullptr), stackSize(stack_size), guardPage(nullptr),
+    guardPageSize(sysconf(_SC_PAGE_SIZE)), started(false), _finished(false)
 {
+    if (stack_size) {
+        guardPage = mmap(nullptr, guardPageSize + stack_size,
+                         PROT_READ | PROT_WRITE,
+                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+        if (guardPage == (void *)MAP_FAILED) {
+            perror("mmap");
+            fatal("Could not mmap %d byte fiber stack.\n", stack_size);
+        }
+        stack = (void *)((uint8_t *)guardPage + guardPageSize);
+        if (mprotect(guardPage, guardPageSize, PROT_NONE)) {
+            perror("mprotect");
+            fatal("Could not forbid access to fiber stack guard page.");
+        }
+    }
 #if HAVE_VALGRIND
-    valgrindStackId = VALGRIND_STACK_REGISTER(stack, stack + stack_size);
+    valgrindStackId = VALGRIND_STACK_REGISTER(
+            stack, (uint8_t *)stack + stack_size);
 #endif
 }
 
-Fiber::Fiber(Fiber *link, size_t stack_size) :
-    link(link), stack(stack_size ? new uint8_t[stack_size] : nullptr),
-    stackSize(stack_size), started(false), _finished(false)
-{}
-
 Fiber::~Fiber()
 {
     panic_if(stack && _currentFiber == this, "Fiber stack is in use.");
 #if HAVE_VALGRIND
     VALGRIND_STACK_DEREGISTER(valgrindStackId);
 #endif
-    delete [] stack;
+    if (guardPage)
+        munmap(guardPage, guardPageSize + stackSize);
 }
 
 void
index 3d82075f0b6f24ad49f81f59dd02fc16eef80003..4d95e032bc47320b0b695d4ec1ac412aa7cef0a5 100644 (file)
@@ -106,8 +106,10 @@ class Fiber
     Fiber *link;
 
     // The stack for this context, or a nullptr if allocated elsewhere.
-    uint8_t *stack;
+    void *stack;
     size_t stackSize;
+    void *guardPage;
+    size_t guardPageSize;
 #if HAVE_VALGRIND
     unsigned valgrindStackId;
 #endif