[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