[vmkit-commits] [vmkit] r144506 - in /vmkit/trunk: include/mvm/System.h include/mvm/Threads/Thread.h include/mvm/VirtualMachine.h lib/J3/Compiler/JavaJIT.cpp lib/J3/VMCore/Jnjvm.cpp lib/J3/VMCore/Jnjvm.h lib/Mvm/CommonThread/Makefile lib/Mvm/CommonThread/Sigsegv-linux-x64.inc lib/Mvm/CommonThread/Sigsegv-macos-x64.inc lib/Mvm/CommonThread/Sigsegv.cpp lib/Mvm/CommonThread/ctthread.cpp

Nicolas Geoffray nicolas.geoffray at lip6.fr
Sun Nov 13 13:54:06 PST 2011


Author: geoffray
Date: Sun Nov 13 15:54:06 2011
New Revision: 144506

URL: http://llvm.org/viewvc/llvm-project?rev=144506&view=rev
Log:
Use the segmentation fault handler to handle stack overflow errors.


Added:
    vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-linux-x64.inc
    vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-macos-x64.inc
Modified:
    vmkit/trunk/include/mvm/System.h
    vmkit/trunk/include/mvm/Threads/Thread.h
    vmkit/trunk/include/mvm/VirtualMachine.h
    vmkit/trunk/lib/J3/Compiler/JavaJIT.cpp
    vmkit/trunk/lib/J3/VMCore/Jnjvm.cpp
    vmkit/trunk/lib/J3/VMCore/Jnjvm.h
    vmkit/trunk/lib/Mvm/CommonThread/Makefile
    vmkit/trunk/lib/Mvm/CommonThread/Sigsegv.cpp
    vmkit/trunk/lib/Mvm/CommonThread/ctthread.cpp

Modified: vmkit/trunk/include/mvm/System.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/include/mvm/System.h?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/include/mvm/System.h (original)
+++ vmkit/trunk/include/mvm/System.h Sun Nov 13 15:54:06 2011
@@ -127,6 +127,11 @@
     return kThreadStart;
   }
 
+  static uint32_t GetPageSize() {
+    static uint32_t pagesize = getpagesize();
+    return pagesize;
+  }
+
   static word_t GetCallerAddress() {
 #if defined(ARCH_X86) || defined(ARCH_X64)
     return (word_t)__builtin_frame_address(0);
@@ -215,13 +220,8 @@
     _exit(value);
   }
 
-  static bool SupportsHardwareNullCheck() {
-#if (LINUX_OS && ARCH_X64) || (MACOS_OS && ARCH_X64)
-    return true;
-#else
-    return false;
-#endif
-  }
+  static bool SupportsHardwareNullCheck();
+  static bool SupportsHardwareStackOverflow();
 };
 
 }

Modified: vmkit/trunk/include/mvm/Threads/Thread.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/include/mvm/Threads/Thread.h?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/include/mvm/Threads/Thread.h (original)
+++ vmkit/trunk/include/mvm/Threads/Thread.h Sun Nov 13 15:54:06 2011
@@ -279,6 +279,24 @@
   void endKnownFrame();
   void startUnknownFrame(KnownFrame& F) __attribute__ ((noinline));
   void endUnknownFrame();
+
+  word_t GetAlternativeStackEnd() {
+    return (word_t)this + System::GetPageSize();
+  }
+
+  word_t GetAlternativeStackStart() {
+    return GetAlternativeStackEnd() + GetAlternativeStackSize();
+  }
+
+  static word_t GetAlternativeStackSize() {
+    return 3 * System::GetPageSize();
+  }
+
+  bool IsStackOverflowAddr(word_t addr) {
+    word_t stackOverflowCheck = GetAlternativeStackStart();
+    return addr > stackOverflowCheck &&
+      addr <= stackOverflowCheck + System::GetPageSize();
+  }
 };
 
 class ExceptionBuffer {

Modified: vmkit/trunk/include/mvm/VirtualMachine.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/include/mvm/VirtualMachine.h?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/include/mvm/VirtualMachine.h (original)
+++ vmkit/trunk/include/mvm/VirtualMachine.h Sun Nov 13 15:54:06 2011
@@ -230,6 +230,7 @@
 //===----------------------------------------------------------------------===//
 
   virtual void nullPointerException() = 0;
+  virtual void stackOverflowError() = 0;
 };
 
 } // end namespace mvm

Modified: vmkit/trunk/lib/J3/Compiler/JavaJIT.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/J3/Compiler/JavaJIT.cpp?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/lib/J3/Compiler/JavaJIT.cpp (original)
+++ vmkit/trunk/lib/J3/Compiler/JavaJIT.cpp Sun Nov 13 15:54:06 2011
@@ -1120,7 +1120,8 @@
     currentBlock = continueBlock;
   }
   
-  if (TheCompiler->hasExceptionsEnabled()) {
+  if (TheCompiler->hasExceptionsEnabled() &&
+      !mvm::System::SupportsHardwareStackOverflow()) {
     // Variables have been allocated and the lock has been taken. Do the stack
     // check now: if there is an exception, we will go to the lock release code.
     currentExceptionBlock = opcodeInfos[0].exceptionBlock;

Modified: vmkit/trunk/lib/J3/VMCore/Jnjvm.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/J3/VMCore/Jnjvm.cpp?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/lib/J3/VMCore/Jnjvm.cpp (original)
+++ vmkit/trunk/lib/J3/VMCore/Jnjvm.cpp Sun Nov 13 15:54:06 2011
@@ -357,6 +357,11 @@
   return obj;
 }
 
+void Jnjvm::stackOverflowError() {
+  JavaThread::get()->throwException(CreateStackOverflowError());
+  UNREACHABLE();
+}
+
 JavaObject* Jnjvm::CreateArrayStoreException(JavaVirtualTable* VT) {
   JavaString* str = NULL;
   llvm_gcroot(str, 0);

Modified: vmkit/trunk/lib/J3/VMCore/Jnjvm.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/J3/VMCore/Jnjvm.h?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/lib/J3/VMCore/Jnjvm.h (original)
+++ vmkit/trunk/lib/J3/VMCore/Jnjvm.h Sun Nov 13 15:54:06 2011
@@ -287,6 +287,7 @@
   void noClassDefFoundError(UserClass* cl, const UTF8* name);
   void classFormatError(const char* str);
   virtual void nullPointerException();
+  virtual void stackOverflowError();
   
   /// asciizToStr - Constructs a java/lang/String object from the given asciiz.
   ///

Modified: vmkit/trunk/lib/Mvm/CommonThread/Makefile
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/Mvm/CommonThread/Makefile?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/lib/Mvm/CommonThread/Makefile (original)
+++ vmkit/trunk/lib/Mvm/CommonThread/Makefile Sun Nov 13 15:54:06 2011
@@ -8,6 +8,8 @@
 ##===----------------------------------------------------------------------===##
 LEVEL = ../../..
 
+EXTRA_DIST = Sigsegv-linux-x64.inc Sigsegv-macos-x64.inc
+
 include $(LEVEL)/Makefile.config
 
 MODULE_WITH_GC = CommonThread

Added: vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-linux-x64.inc
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-linux-x64.inc?rev=144506&view=auto
==============================================================================
--- vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-linux-x64.inc (added)
+++ vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-linux-x64.inc Sun Nov 13 15:54:06 2011
@@ -0,0 +1,53 @@
+//===-------- Sigsegv-linux-x64.inc - Sigsegv handling --------------------===//
+//
+//                     The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+  void HandleNullPointer(void);
+  asm(
+    ".text\n"
+    ".align 8\n"
+    ".globl HandleNullPointer\n"
+  "HandleNullPointer:\n"
+    // Save the faulting address to fake a real method call.
+    "pushq %rdi\n"
+    "jmp   ThrowNullPointerException\n"
+    );
+  
+  void HandleStackOverflow(void);
+  asm(
+    ".text\n"
+    ".align 8\n"
+    ".globl HandleStackOverflow\n"
+  "HandleStackOverflow:\n"
+    "pushq %rbp\n"
+    "movq %rsi, %rbp\n"
+    "callq   ThrowStackOverflowError\n"
+    );
+}
+
+void Handler::UpdateRegistersForNPE() {
+  ((ucontext_t*)context)->uc_mcontext.gregs[REG_RDI] = ((ucontext_t*)context)->uc_mcontext.gregs[REG_RIP] + 1;
+  ((ucontext_t*)context)->uc_mcontext.gregs[REG_RIP] = (word_t)HandleNullPointer;
+}
+
+void Handler::UpdateRegistersForStackOverflow() {
+  word_t alt_stack = mvm::Thread::get()->GetAlternativeStackStart();
+  ((ucontext_t*)context)->uc_mcontext.gregs[REG_RDI] = System::GetIPFromCallerAddress(((ucontext_t*)context)->uc_mcontext.gregs[REG_RBP]);
+  ((ucontext_t*)context)->uc_mcontext.gregs[REG_RSI] = ((ucontext_t*)context)->uc_mcontext.gregs[REG_RBP];
+  ((ucontext_t*)context)->uc_mcontext.gregs[REG_RSP] = alt_stack;
+  ((ucontext_t*)context)->uc_mcontext.gregs[REG_RIP] = (word_t)HandleStackOverflow;
+}
+
+bool System::SupportsHardwareNullCheck() {
+  return true;
+}
+
+bool System::SupportsHardwareStackOverflow() {
+  return true;
+}

Added: vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-macos-x64.inc
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-macos-x64.inc?rev=144506&view=auto
==============================================================================
--- vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-macos-x64.inc (added)
+++ vmkit/trunk/lib/Mvm/CommonThread/Sigsegv-macos-x64.inc Sun Nov 13 15:54:06 2011
@@ -0,0 +1,38 @@
+//---------- Sigsegv-macos-x64.inc - Sigsegv handling ---------------------===//
+//
+//                     The VMKit project
+//
+// This file is distributed under the University of Illinois Open Source 
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+  void HandleNullPointer(void);
+  asm(
+    ".text\n"
+    ".align 8\n"
+    ".globl HandleNullPointer\n"
+  "_HandleNullPointer:\n"
+    // Save the faulting address to fake a real method call.
+    "pushq %rdi\n"
+    "jmp   _ThrowNullPointerException\n"
+    );
+}
+
+void Handler::UpdateRegistersForNPE() {
+  ((ucontext_t*)context)->uc_mcontext->__ss.__rdi = ((ucontext_t*)context)->uc_mcontext->__ss.__rip + 1;
+  ((ucontext_t*)context)->uc_mcontext->__ss.__rip = (word_t)HandleNullPointer;
+}
+
+void Handler::UpdateRegistersForStackOverflow() {
+  UNREACHABLE();
+}
+
+bool System::SupportsHardwareNullCheck() {
+  return true;
+}
+
+bool System::SupportsHardwareStackOverflow() {
+  return false;
+}

Modified: vmkit/trunk/lib/Mvm/CommonThread/Sigsegv.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/Mvm/CommonThread/Sigsegv.cpp?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/lib/Mvm/CommonThread/Sigsegv.cpp (original)
+++ vmkit/trunk/lib/Mvm/CommonThread/Sigsegv.cpp Sun Nov 13 15:54:06 2011
@@ -18,46 +18,50 @@
 
 using namespace mvm;
 
-#if defined(ARCH_X64) && defined(LINUX_OS)
-
-extern "C" {
-  void NativeHandleSignal(void);
-  asm(
-    ".text\n"
-    ".align 8\n"
-    ".globl NativeHandleSignal\n"
-  "NativeHandleSignal:\n"
-    // Save The faulting address to fake a reall method call
-    "pushq %rdi\n"
-    "jmp   ThrowNullPointerException\n"
-    );
-}
-
-#define UPDATE_REGS() \
-    ((ucontext_t*)context)->uc_mcontext.gregs[REG_RDI] = ((ucontext_t*)context)->uc_mcontext.gregs[REG_RIP] + 1; \
-    ((ucontext_t*)context)->uc_mcontext.gregs[REG_RIP] = (word_t)NativeHandleSignal;
+namespace {
+  class Handler {
+    void* context;
+  public:
+    Handler(void* ucontext): context(ucontext) {}
+    void UpdateRegistersForNPE();
+    void UpdateRegistersForStackOverflow();
+  };
+}
 
+#if defined(ARCH_X64) && defined(LINUX_OS)
+#include "Sigsegv-linux-x64.inc"
 #elif defined(ARCH_X64) && defined(MACOS_OS)
-extern "C" {
-  void NativeHandleSignal(void);
-  asm(
-    ".text\n"
-    ".align 8\n"
-    ".globl NativeHandleSignal\n"
-  "_NativeHandleSignal:\n"
-    // Save The faulting address to fake a reall method call
-    "pushq %rdi\n"
-    "jmp   _ThrowNullPointerException\n"
-    );
-}
-
-#define UPDATE_REGS() \
-    ((ucontext_t*)context)->uc_mcontext->__ss.__rdi = ((ucontext_t*)context)->uc_mcontext->__ss.__rip + 1; \
-    ((ucontext_t*)context)->uc_mcontext->__ss.__rip = (word_t)NativeHandleSignal;
+#include "Sigsegv-macos-x64.inc"
 #else
-#define UPDATE_REGS() UNIMPLEMENTED();
+void Handler::UpdateRegistersForStackOverflow() {
+  UNREACHABLE();
+}
+
+void Handler::UpdateRegistersForNPE() {
+  UNREACHABLE();
+}
+
+bool System::SupportsHardwareNullCheck() {
+  return false;
+}
+
+bool System::SupportsHardwareStackOverflow() {
+  return false;
+}
 #endif
 
+extern "C" void ThrowStackOverflowError(word_t ip, word_t fp) {
+  mvm::Thread* th = mvm::Thread::get();
+  mvm::FrameInfo* FI = th->MyVM->IPToFrameInfo(ip);
+  if (FI->Metadata == NULL) {
+    fprintf(stderr, "Thread %p received a SIGSEGV: either the VM code or an external\n"
+                    "native method is bogus. Aborting...\n", (void*)th);
+    abort();
+  } else {
+    mvm::Thread::get()->MyVM->stackOverflowError();
+  }
+  UNREACHABLE();
+}
 
 extern "C" void ThrowNullPointerException(word_t ip) {
   mvm::Thread* th = mvm::Thread::get();
@@ -66,24 +70,34 @@
     fprintf(stderr, "Thread %p received a SIGSEGV: either the VM code or an external\n"
                     "native method is bogus. Aborting...\n", (void*)th);
     abort();
+  } else {
+    mvm::Thread::get()->MyVM->nullPointerException();
   }
-  mvm::Thread::get()->MyVM->nullPointerException();
   UNREACHABLE();
 }
 
-void sigsegvHandler(int n, siginfo_t *_info, void *context) {
+void sigsegvHandler(int n, siginfo_t *info, void *context) {
+  Handler handler(context);
   mvm::Thread* th = mvm::Thread::get();
-  word_t addr = (word_t)_info->si_addr;
-  if (addr > (word_t)th->getThreadID() && addr < (word_t)th->baseSP) {
-    fprintf(stderr, "Stack overflow in VM code or in JNI code. If it is from\n"
-                    "the VM, it is either from the JIT, the GC or the runtime."
-                    "\nThis has to be fixed in the VM: VMKit makes sure that\n"
-                    "the bottom of the stack is always available when entering"
-                    "\nthe VM.\n");
-    abort();
-  } else if (mvm::System::SupportsHardwareNullCheck()) {
-    UPDATE_REGS();
+  word_t addr = (word_t)info->si_addr;
+  if (th->IsStackOverflowAddr(addr)) {
+    if (mvm::System::SupportsHardwareStackOverflow()) {
+      handler.UpdateRegistersForStackOverflow();
+    } else {
+      fprintf(stderr, "Stack overflow in VM code or in JNI code. If it is from\n"
+                      "the VM, it is either from the JIT, the GC or the runtime."
+                      "\nThis has to be fixed in the VM: VMKit makes sure that\n"
+                      "the bottom of the stack is always available when entering"
+                      "\nthe VM.\n");
+      abort();
+    }
   } else {
-    abort();
+    if (mvm::System::SupportsHardwareNullCheck()) {
+      handler.UpdateRegistersForNPE();
+    } else {
+      fprintf(stderr, "Thread %p received a SIGSEGV: either the VM code or an external\n"
+                      "native method is bogus. Aborting...\n", (void*)th);
+      abort();
+    }
   }
 }

Modified: vmkit/trunk/lib/Mvm/CommonThread/ctthread.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/Mvm/CommonThread/ctthread.cpp?rev=144506&r1=144505&r2=144506&view=diff
==============================================================================
--- vmkit/trunk/lib/Mvm/CommonThread/ctthread.cpp (original)
+++ vmkit/trunk/lib/Mvm/CommonThread/ctthread.cpp Sun Nov 13 15:54:06 2011
@@ -278,12 +278,11 @@
       abort();
     }
  
-    // Protect the page after the first page. The first page contains thread
-    // specific data. The second page has no access rights to catch stack
-    // overflows.
-    uint32 pagesize = getpagesize();
+    // Protect the page after the alternative stack.
+    uint32 pagesize = System::GetPageSize();
     for (uint32 i = 0; i < NR_THREADS; ++i) {
-      word_t addr = baseAddr + (i * STACK_SIZE) + pagesize;
+      word_t addr = baseAddr + (i * STACK_SIZE) + pagesize
+        + mvm::Thread::GetAlternativeStackSize();
       mprotect((void*)addr, pagesize, PROT_NONE);
     }
 
@@ -327,11 +326,19 @@
 void Thread::internalThreadStart(mvm::Thread* th) {
   th->baseSP  = System::GetCallerAddress();
 
+  // Set the alternate stack as the second page of the thread's
+  // stack.
+  stack_t st;
+  st.ss_sp = (void*)th->GetAlternativeStackEnd();
+  st.ss_flags = 0;
+  st.ss_size = th->GetAlternativeStackSize();
+  sigaltstack(&st, NULL);
+
   // Set the SIGSEGV handler to diagnose errors.
   struct sigaction sa;
   sigset_t mask;
   sigfillset(&mask);
-  sa.sa_flags = SA_SIGINFO;
+  sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
   sa.sa_mask = mask;
   sa.sa_sigaction = sigsegvHandler;
   sigaction(SIGSEGV, &sa, NULL);





More information about the vmkit-commits mailing list