[strongtalk] r195 committed - Detect stack overflows and suspend overflowing DeltaProcess

6 views
Skip to first unread message

codesite...@google.com

unread,
Dec 29, 2009, 9:49:57 PM12/29/09
to strongta...@googlegroups.com
Revision: 195
Author: StephenLRees
Date: Tue Dec 29 18:48:47 2009
Log: Detect stack overflows and suspend overflowing DeltaProcess
http://code.google.com/p/strongtalk/source/detail?r=195

Modified:
/branches/gcc-linux/test/main/main.cpp
/branches/gcc-linux/vm/compiler/codeGenerator.cpp
/branches/gcc-linux/vm/compiler/oldCodeGenerator.cpp
/branches/gcc-linux/vm/interpreter/interpreter.cpp
/branches/gcc-linux/vm/runtime/os.hpp
/branches/gcc-linux/vm/runtime/os_nt.cpp
/branches/gcc-linux/vm/runtime/process.cpp
/branches/gcc-linux/vm/runtime/process.hpp

=======================================
--- /branches/gcc-linux/test/main/main.cpp Mon Dec 28 10:47:15 2009
+++ /branches/gcc-linux/test/main/main.cpp Tue Dec 29 18:48:47 2009
@@ -64,7 +64,9 @@
int ignore;
Processes::remove(this);
os::terminate_thread(_thread); // don't want to launch delta!
- os::create_thread((int (*)(void*)) &launch_tests, this, &ignore);
+ _thread = os::create_thread((int (*)(void*)) &launch_tests, this,
&ignore);
+ _stack_limit = (char*)os::stack_limit(_thread);
+
oop process = newProcess();
assert(process->is_process(), "Should be process");
set_processObj(processOop(process));
@@ -74,7 +76,9 @@
int ignore;
Processes::remove(this);
os::terminate_thread(_thread); // don't want to launch delta!
- os::create_thread((osfn) launchfn, this, &ignore);
+ _thread = os::create_thread((osfn) launchfn, this, &ignore);
+ _stack_limit = (char*)os::stack_limit(_thread);
+
oop process = newProcess();
assert(process->is_process(), "Should be process");
set_processObj(processOop(process));
=======================================
--- /branches/gcc-linux/vm/compiler/codeGenerator.cpp Sat Nov 1 12:10:49
2008
+++ /branches/gcc-linux/vm/compiler/codeGenerator.cpp Tue Dec 29 18:48:47
2009
@@ -817,6 +817,8 @@


// Individual nodes
+extern "C" char* active_stack_limit();
+extern "C" void check_stack_overflow();

void CodeGenerator::aPrologueNode(PrologueNode* node) {
// set unverified entry point
@@ -902,6 +904,11 @@
Label start;
_masm->jmp(start);

+ Label handle_stack_overflow, continue_after_stack_overflow;
+ _masm->bind(handle_stack_overflow);
+ _masm->call_C((char*)&check_stack_overflow,
relocInfo::runtime_call_type);
+ _masm->jmp(continue_after_stack_overflow);
+
// call to recompiler - if the nmethod turns zombie, this will be
overwritten
// by a call to the zombie handler (see also comment in nmethod)
_masm->bind(recompile_stub_call);
@@ -910,6 +917,9 @@
_masm->call(StubRoutines::recompile_stub_entry(),
relocInfo::runtime_call_type);

_masm->bind(start);
+ _masm->cmpl(esp, Address(int(active_stack_limit()),
relocInfo::external_word_type));
+ _masm->jcc(Assembler::less, handle_stack_overflow);
+ _masm->bind(continue_after_stack_overflow);
}


=======================================
--- /branches/gcc-linux/vm/compiler/oldCodeGenerator.cpp Mon Nov 12
14:26:32 2007
+++ /branches/gcc-linux/vm/compiler/oldCodeGenerator.cpp Tue Dec 29
18:48:47 2009
@@ -646,10 +646,18 @@
// otherwise continue
}

+extern "C" void check_stack_overflow();
+extern "C" char* active_stack_limit();

void PrologueNode::gen() {
BasicNode::gen();

+ // stub for handling stack overflows
+ Label handle_stack_overflow, continue_after_stack_overflow;
+ theMacroAssm->bind(handle_stack_overflow);
+ theMacroAssm->call_C((char*)&check_stack_overflow,
relocInfo::runtime_call_type);
+ theMacroAssm->jmp(continue_after_stack_overflow);
+
// call to recompiler - if the nmethod turns zombie, this will be
overwritten by a call to the zombie handler
// (see also comment in nmethod)
Label recompile_stub_call;
@@ -755,6 +763,10 @@
}
// check for recompilation (do this last so stack frame is initialized
properly)
checkRecompilation(recompile_stub_call, temp2);
+
+ theMacroAssm->cmpl(esp, Address(int(active_stack_limit()),
relocInfo::external_word_type));
+ theMacroAssm->jcc(Assembler::less, handle_stack_overflow);
+ theMacroAssm->bind(continue_after_stack_overflow);
}


=======================================
--- /branches/gcc-linux/vm/interpreter/interpreter.cpp Sun Jun 7 11:33:29
2009
+++ /branches/gcc-linux/vm/interpreter/interpreter.cpp Tue Dec 29 18:48:47
2009
@@ -2124,7 +2124,14 @@

extern "C" char* method_entry_point = NULL; // for interpreter_asm.asm
(remove if not used anymore)
extern "C" char* block_entry_point = NULL; // for interpreter_asm.asm
(remove if not used anymore)
-
+extern "C" char* active_stack_limit(); // address of
pointer to the current process' stack limit
+
+extern "C" void check_stack_overflow() {
+ if (!DeltaProcess::active()->is_scheduler())
+ DeltaProcess::active()->suspend(stack_overflow);
+ else
+ fatal("Stack overflow in scheduler");
+}
void InterpreterGenerator::generate_method_entry_code() {
// This generates the code sequence called to activate methodOop execution.
// It is usually called via the call_method() macro, which saves the old
@@ -2134,7 +2141,8 @@
const int code_offset = methodOopDesc::codes_byte_offset();

assert(!_method_entry.is_bound(), "code has been generated before");
- Label start_setup, counter_overflow, start_execution,
handle_counter_overflow, is_interpreted;
+ Label start_setup, counter_overflow, start_execution,
handle_counter_overflow, is_interpreted,
+ handle_stack_overflow, continue_from_stack_overflow;

// eax: receiver
// ebx: 000000xx
@@ -2163,6 +2171,9 @@
masm->jcc(Assembler::aboveEqual, counter_overflow); // treat
invocation counter overflow
masm->bind(start_execution); // continuation point after overflow
masm->movl(eax, edi); // initialize temp0
+ masm->cmpl(esp, Address(int(active_stack_limit()),
relocInfo::external_word_type));
+ masm->jcc(Assembler::lessEqual, handle_stack_overflow);
+ masm->bind(continue_from_stack_overflow);
jump_ebx(); // start execution

// invocation counter overflow
@@ -2221,6 +2232,10 @@
// edi: context (= initial value for temp0)
// parameters on stack
masm->jmp(start_setup);
+
+ masm->bind(handle_stack_overflow);
+ masm->call_C((char*)&check_stack_overflow,
relocInfo::external_word_type);
+ masm->jmp(continue_from_stack_overflow);
}


=======================================
--- /branches/gcc-linux/vm/runtime/os.hpp Sun Aug 9 17:16:11 2009
+++ /branches/gcc-linux/vm/runtime/os.hpp Tue Dec 29 18:48:47 2009
@@ -79,6 +79,7 @@
static Thread* starting_thread(int* id_addr);
static Thread* create_thread(int main(void* parameter), void* parameter,
int* id_addr);
static Event* create_event(bool initial_state);
+ static void* stack_limit(Thread* thread);

static int current_thread_id();
static void wait_for_event(Event* event);
=======================================
--- /branches/gcc-linux/vm/runtime/os_nt.cpp Sun Dec 13 16:47:01 2009
+++ /branches/gcc-linux/vm/runtime/os_nt.cpp Tue Dec 29 18:48:47 2009
@@ -27,12 +27,94 @@

#include <windows.h>
#include <signal.h>
-
+typedef struct _thread_start {
+ int (*main)(void*);
+ void* parameter;
+ void* stackLimit;
+} thread_start;
+
+int WINAPI startThread(void* params);
+#define STACK_SIZE 512*1024
+
+class Thread : public CHeapObj {
+ static GrowableArray<Thread*>* threads;
+ static Event* thread_created;
+ HANDLE thread_handle;
+ int thread_id;
+ void* stack_limit;
+
+ static void initialize() {
+ threads = new(true) GrowableArray<Thread*>(10, true);
+ thread_created = os::create_event(false);
+ }
+ static void release() {
+ }
+ static bool equals(void* token, Thread* element) {
+ return token == (void*) element;
+ }
+ Thread(HANDLE handle, int id, void* stackLimit) : thread_handle(handle),
thread_id(id), stack_limit(stackLimit) {
+ int index = threads->find(NULL, equals);
+ if (index < 0)
+ threads->append(this);
+ else
+ threads->at_put(index, this);
+ }
+ virtual ~Thread() {
+ int index = threads->find(this);
+ threads->at_put(index, NULL);
+ }
+
+ static Thread* createThread(int main(void* parameter), void* parameter,
int* id_addr) {
+ ThreadCritical tc;
+ thread_start params;
+ params.main = main;
+ params.parameter = parameter;
+
+ os::reset_event(thread_created);
+ HANDLE result = CreateThread(NULL, STACK_SIZE,
(LPTHREAD_START_ROUTINE) startThread, &params, 0, (unsigned long*) id_addr);
+ if (result == NULL) return NULL;
+
+ os::wait_for_event(thread_created);
+
+ return new Thread(result, *id_addr, params.stackLimit);
+ }
+
+ static Thread* findThread(int thread_id) {
+ for (int index = 0; index < threads->length(); index++) {
+ Thread* thread = threads->at(index);
+ if (thread == NULL) continue;
+ if (thread->thread_id == thread_id)
+ return thread;
+ }
+ return NULL;
+ }
+
+ friend class os;
+ friend int WINAPI startThread(void*);
+ friend void os_init();
+ friend void os_exit();
+};
+
+int WINAPI startThread(void* params) {
+ char* spptr;
+ __asm mov spptr, esp;
+ ((thread_start*) params)->stackLimit = spptr - STACK_SIZE +
os::vm_page_size();
+
+ int (*main)(void*) = ((thread_start*) params)->main;
+ void* parameter = ((thread_start*) params)->parameter;
+
+ os::signal_event(Thread::thread_created);
+ return main(parameter);
+}
+
+Event* Thread::thread_created = NULL;
+GrowableArray<Thread*>* Thread::threads = NULL;

static HANDLE main_process;
-static HANDLE main_thread;
+//static HANDLE main_thread;
static int main_thread_id;
static HANDLE watcher_thread;
+static Thread* main_thread;

static FILETIME process_creation_time;
static FILETIME process_exit_time;
@@ -74,18 +156,22 @@

Thread* os::starting_thread(int* id_addr) {
*id_addr = main_thread_id;
- return (Thread*) main_thread;
+ return main_thread;
}

Thread* os::create_thread(int main(void* parameter), void* parameter, int*
id_addr) {
- HANDLE result = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) main,
parameter, 0, (unsigned long*) id_addr);
- if (result == NULL) return NULL;
- return (Thread*) result;
+ return Thread::createThread(main, parameter, id_addr);
}

+void* os::stack_limit(Thread* thread) {
+ return thread->stack_limit;
+}
void os::terminate_thread(Thread* thread) {
- TerminateThread((HANDLE) thread, 0);
- CloseHandle((HANDLE) thread);
+ HANDLE handle = thread->thread_handle;
+ delete thread;
+
+ TerminateThread(handle, 0);
+ CloseHandle(handle);
}

void os::delete_event(Event* event) {
@@ -352,11 +438,11 @@
}

void os::suspend_thread(Thread* thread) {
- SuspendThread(thread);
+ SuspendThread(thread->thread_handle);
}

void os::resume_thread(Thread* thread) {
- ResumeThread(thread);
+ ResumeThread(thread->thread_handle);
}

void os::sleep(int ms) {
@@ -366,7 +452,7 @@
void os::fetch_top_frame(Thread* thread, int** sp, int** fp, char** pc) {
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
- if (GetThreadContext(thread, &context)) {
+ if (GetThreadContext(thread->thread_handle, &context)) {
*sp = (int*) context.Esp;
*fp = (int*) context.Ebp;
*pc = (char*) context.Eip;
@@ -497,6 +583,7 @@

void os_init() {
ThreadCritical::intialize();
+ Thread::initialize();

if (hInstance == NULL) {
hInstance = GetModuleHandle(NULL);
@@ -520,14 +607,17 @@

SetConsoleCtrlHandler(&HandlerRoutine, TRUE);

+ HANDLE threadHandle;
// Initialize main_process and main_thread
main_process = GetCurrentProcess(); // Remember main_process is a
pseudo handle
if (!DuplicateHandle(main_process, GetCurrentThread(), main_process,
- &main_thread, THREAD_ALL_ACCESS, FALSE, 0)) {
+ &threadHandle, THREAD_ALL_ACCESS, FALSE, 0)) {
fatal("DuplicateHandle failed\n");
}
main_thread_id = (int) GetCurrentThreadId();

+ main_thread = new Thread(threadHandle, main_thread_id, NULL);
+
// Setup Windows Exceptions

SetUnhandledExceptionFilter(topLevelExceptionFilter);
@@ -542,6 +632,7 @@
}

void os_exit() {
+ Thread::release();
ThreadCritical::release();
}

=======================================
--- /branches/gcc-linux/vm/runtime/process.cpp Sun Jun 7 11:33:29 2009
+++ /branches/gcc-linux/vm/runtime/process.cpp Tue Dec 29 18:48:47 2009
@@ -296,8 +296,13 @@

// ======= DeltaProcess ========

+extern "C" char* active_stack_limit() {
+ return (char*) &DeltaProcess::_active_stack_limit;
+}
+
Process* Process::_current_process = NULL;
DeltaProcess* DeltaProcess::_active_delta_process = NULL;
+char* DeltaProcess::_active_stack_limit = NULL;
DeltaProcess* DeltaProcess::_scheduler_process = NULL;
bool DeltaProcess::_is_idle = false;

@@ -486,6 +491,7 @@

_event = os::create_event(false);
_thread = os::create_thread((int (*)(void*)) &launch_delta, (void*)
this, &_thread_id);
+ _stack_limit = (char*)os::stack_limit(_thread);

_unwind_head = NULL;

=======================================
--- /branches/gcc-linux/vm/runtime/process.hpp Mon Dec 28 10:47:15 2009
+++ /branches/gcc-linux/vm/runtime/process.hpp Tue Dec 29 18:48:47 2009
@@ -86,9 +86,10 @@
void basic_transfer(Process* target);

// OS data associated with the process
- Thread* _thread; // Native thread
- int _thread_id; // Native thread id (set by OS when created)
- Event* _event; // Thread lock
+ Thread* _thread; // Native thread
+ int _thread_id; // Native thread id (set by OS when created)
+ Event* _event; // Thread lock
+ char* _stack_limit;// lower limit of stack

static Process* _current_process; // active Delta process or vm
process
};
@@ -171,6 +172,8 @@
}
};

+extern "C" char* active_stack_limit();
+
class DeltaProcess: public Process {
private:
oop _receiver; // receiver of the initial message.
@@ -371,15 +374,17 @@
static DeltaProcess* _active_delta_process;
static DeltaProcess* _scheduler_process;
static bool _is_idle;
+ static char* _active_stack_limit;

// The launch function for a new thread
static int launch_delta(DeltaProcess* process);

public:
-
// sets the active process (note: public only to support testing)
static void set_active(DeltaProcess* p) {
_active_delta_process = p;
+ _active_stack_limit = p->_stack_limit;
+
if (_active_delta_process->state() != uncommon) {
_active_delta_process->set_state(running);
}
@@ -427,6 +432,8 @@
// async dll completes
static Event* _async_dll_completion_event;
friend class VMProcess; // to allow access to _process_has_terminated
+ friend class InterpreterGenerator;
+ friend char* active_stack_limit();
};


Reply all
Reply to author
Forward
0 new messages