vm: more defense against multi-faulting
* Clear faulting_p from a safepoint rather than inside general_error, because jumping into unwind-native-frames could blow up. * Handle multiple faults from fatal_error by breakpointing. Is there anything else we can safely do at that point? * Verify memory protection faults in the top half of the signal handlers because signal dispatch could fault. Treat memory faults during gc or fep as fatal errors. * Add a function factor_vm::abort() that restores the default SIGABRT handler and ::abort()s. Use it from fatal_error() so we get useful context from gdb and so the user gets feedback from the system crash reporter that Factor blew up and didn't just disappear. * In factorbug(), don't proceed with .s .r .c if it would be unsafe to do so. * Don't pile on signals if we've already called fatal_error().db4
parent
6cca0ea468
commit
e24400679f
|
@ -140,12 +140,17 @@ IN: bootstrap.x86
|
||||||
[ jit-jump-quot ]
|
[ jit-jump-quot ]
|
||||||
\ (call) define-combinator-primitive
|
\ (call) define-combinator-primitive
|
||||||
|
|
||||||
|
: (jit-safepoint) ( -- )
|
||||||
|
0 EAX MOVABS rc-absolute rel-safepoint ;
|
||||||
[
|
[
|
||||||
! Load ds and rs registers
|
! Load ds and rs registers
|
||||||
jit-load-vm
|
jit-load-vm
|
||||||
jit-load-context
|
jit-load-context
|
||||||
jit-restore-context
|
jit-restore-context
|
||||||
|
|
||||||
|
! Safepoint to clear the faulting flag in the VM
|
||||||
|
(jit-safepoint)
|
||||||
|
|
||||||
! Windows-specific setup
|
! Windows-specific setup
|
||||||
ctx-reg jit-update-seh
|
ctx-reg jit-update-seh
|
||||||
|
|
||||||
|
@ -395,9 +400,7 @@ IN: bootstrap.x86
|
||||||
EAX EDX [] MOV
|
EAX EDX [] MOV
|
||||||
jit-jump-quot ;
|
jit-jump-quot ;
|
||||||
|
|
||||||
[
|
[ (jit-safepoint) ] \ jit-safepoint jit-define
|
||||||
0 EAX MOVABS rc-absolute rel-safepoint
|
|
||||||
] \ jit-safepoint jit-define
|
|
||||||
|
|
||||||
[
|
[
|
||||||
jit-start-context-and-delete
|
jit-start-context-and-delete
|
||||||
|
|
|
@ -122,6 +122,9 @@ IN: bootstrap.x86
|
||||||
[ jit-jump-quot ]
|
[ jit-jump-quot ]
|
||||||
\ (call) define-combinator-primitive
|
\ (call) define-combinator-primitive
|
||||||
|
|
||||||
|
: (jit-safepoint)
|
||||||
|
0 [RIP+] EAX MOV rc-relative rel-safepoint ;
|
||||||
|
|
||||||
[
|
[
|
||||||
! Unwind stack frames
|
! Unwind stack frames
|
||||||
RSP arg2 MOV
|
RSP arg2 MOV
|
||||||
|
@ -134,6 +137,9 @@ IN: bootstrap.x86
|
||||||
jit-load-context
|
jit-load-context
|
||||||
jit-restore-context
|
jit-restore-context
|
||||||
|
|
||||||
|
! Safepoint to clear the faulting flag in the VM
|
||||||
|
(jit-safepoint)
|
||||||
|
|
||||||
! Call quotation
|
! Call quotation
|
||||||
jit-jump-quot
|
jit-jump-quot
|
||||||
] \ unwind-native-frames define-sub-primitive
|
] \ unwind-native-frames define-sub-primitive
|
||||||
|
@ -336,9 +342,7 @@ IN: bootstrap.x86
|
||||||
jit-push-param
|
jit-push-param
|
||||||
jit-jump-quot ;
|
jit-jump-quot ;
|
||||||
|
|
||||||
[
|
[ (jit-safepoint) ] \ jit-safepoint jit-define
|
||||||
0 [RIP+] EAX MOV rc-relative rel-safepoint
|
|
||||||
] \ jit-safepoint jit-define
|
|
||||||
|
|
||||||
[
|
[
|
||||||
jit-start-context-and-delete
|
jit-start-context-and-delete
|
||||||
|
|
|
@ -2,16 +2,16 @@ USING: arrays byte-arrays kernel kernel.private math memory
|
||||||
namespaces sequences tools.test math.private quotations
|
namespaces sequences tools.test math.private quotations
|
||||||
continuations prettyprint io.streams.string debugger assocs
|
continuations prettyprint io.streams.string debugger assocs
|
||||||
sequences.private accessors locals.backend grouping words
|
sequences.private accessors locals.backend grouping words
|
||||||
system ;
|
system alien alien.accessors ;
|
||||||
IN: kernel.tests
|
IN: kernel.tests
|
||||||
|
|
||||||
[ 0 ] [ f size ] unit-test
|
[ 0 ] [ f size ] unit-test
|
||||||
[ t ] [ [ \ = \ = ] all-equal? ] unit-test
|
[ t ] [ [ \ = \ = ] all-equal? ] unit-test
|
||||||
|
|
||||||
! Don't leak extra roots if error is thrown
|
! Don't leak extra roots if error is thrown
|
||||||
[ ] [ 10000 [ [ 3 throw ] ignore-errors ] times ] unit-test
|
[ ] [ 1000 [ [ 3 throw ] ignore-errors ] times ] unit-test
|
||||||
|
|
||||||
[ ] [ 10000 [ [ -1 f <array> ] ignore-errors ] times ] unit-test
|
[ ] [ 1000 [ [ -1 f <array> ] ignore-errors ] times ] unit-test
|
||||||
|
|
||||||
! Make sure we report the correct error on stack underflow
|
! Make sure we report the correct error on stack underflow
|
||||||
[ clear drop ] [ { "kernel-error" 10 f f } = ] must-fail-with
|
[ clear drop ] [ { "kernel-error" 10 f f } = ] must-fail-with
|
||||||
|
@ -183,3 +183,7 @@ os windows? [
|
||||||
[ t ] [ { } identity-hashcode fixnum? ] unit-test
|
[ t ] [ { } identity-hashcode fixnum? ] unit-test
|
||||||
[ 123 ] [ 123 identity-hashcode ] unit-test
|
[ 123 ] [ 123 identity-hashcode ] unit-test
|
||||||
[ t ] [ f identity-hashcode fixnum? ] unit-test
|
[ t ] [ f identity-hashcode fixnum? ] unit-test
|
||||||
|
|
||||||
|
! Make sure memory protection faults work
|
||||||
|
[ f 0 alien-unsigned-1 ] [ vm-error? ] must-fail-with
|
||||||
|
[ 1 <alien> 0 alien-unsigned-1 ] [ vm-error? ] must-fail-with
|
||||||
|
|
17
vm/debug.cpp
17
vm/debug.cpp
|
@ -201,13 +201,19 @@ void factor_vm::print_objects(cell *start, cell *end)
|
||||||
void factor_vm::print_datastack()
|
void factor_vm::print_datastack()
|
||||||
{
|
{
|
||||||
std::cout << "==== DATA STACK:" << std::endl;
|
std::cout << "==== DATA STACK:" << std::endl;
|
||||||
|
if (ctx)
|
||||||
print_objects((cell *)ctx->datastack_seg->start,(cell *)ctx->datastack);
|
print_objects((cell *)ctx->datastack_seg->start,(cell *)ctx->datastack);
|
||||||
|
else
|
||||||
|
std::cout << "*** Context not initialized" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::print_retainstack()
|
void factor_vm::print_retainstack()
|
||||||
{
|
{
|
||||||
std::cout << "==== RETAIN STACK:" << std::endl;
|
std::cout << "==== RETAIN STACK:" << std::endl;
|
||||||
|
if (ctx)
|
||||||
print_objects((cell *)ctx->retainstack_seg->start,(cell *)ctx->retainstack);
|
print_objects((cell *)ctx->retainstack_seg->start,(cell *)ctx->retainstack);
|
||||||
|
else
|
||||||
|
std::cout << "*** Context not initialized" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stack_frame_printer {
|
struct stack_frame_printer {
|
||||||
|
@ -238,9 +244,14 @@ struct stack_frame_printer {
|
||||||
void factor_vm::print_callstack()
|
void factor_vm::print_callstack()
|
||||||
{
|
{
|
||||||
std::cout << "==== CALL STACK:" << std::endl;
|
std::cout << "==== CALL STACK:" << std::endl;
|
||||||
|
if (ctx)
|
||||||
|
{
|
||||||
stack_frame_printer printer(this);
|
stack_frame_printer printer(this);
|
||||||
iterate_callstack(ctx,printer);
|
iterate_callstack(ctx,printer);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
std::cout << "*** Context not initialized" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
struct padded_address {
|
struct padded_address {
|
||||||
cell value;
|
cell value;
|
||||||
|
@ -450,6 +461,8 @@ void factor_vm::factorbug_usage(bool advanced_p)
|
||||||
std::cout << " push <addr> -- push object on data stack - NOT SAFE" << std::endl;
|
std::cout << " push <addr> -- push object on data stack - NOT SAFE" << std::endl;
|
||||||
std::cout << " gc -- trigger full GC - NOT SAFE" << std::endl;
|
std::cout << " gc -- trigger full GC - NOT SAFE" << std::endl;
|
||||||
std::cout << " code -- code heap dump" << std::endl;
|
std::cout << " code -- code heap dump" << std::endl;
|
||||||
|
std::cout << " abort -- call abort()" << std::endl;
|
||||||
|
std::cout << " breakpoint -- trigger system breakpoint" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -599,6 +612,10 @@ void factor_vm::factorbug()
|
||||||
primitive_full_gc();
|
primitive_full_gc();
|
||||||
else if(strcmp(cmd,"help") == 0)
|
else if(strcmp(cmd,"help") == 0)
|
||||||
factorbug_usage(true);
|
factorbug_usage(true);
|
||||||
|
else if(strcmp(cmd,"abort") == 0)
|
||||||
|
abort();
|
||||||
|
else if(strcmp(cmd,"breakpoint") == 0)
|
||||||
|
breakpoint();
|
||||||
else
|
else
|
||||||
std::cout << "unknown command" << std::endl;
|
std::cout << "unknown command" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,26 @@
|
||||||
namespace factor
|
namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
|
bool factor_vm::fatal_erroring_p;
|
||||||
|
|
||||||
|
static inline void fa_diddly_atal_error()
|
||||||
|
{
|
||||||
|
printf("fatal_error in fatal_error!\n");
|
||||||
|
breakpoint();
|
||||||
|
exit(86);
|
||||||
|
}
|
||||||
|
|
||||||
void fatal_error(const char *msg, cell tagged)
|
void fatal_error(const char *msg, cell tagged)
|
||||||
{
|
{
|
||||||
|
if (factor_vm::fatal_erroring_p)
|
||||||
|
fa_diddly_atal_error();
|
||||||
|
|
||||||
|
factor_vm::fatal_erroring_p = true;
|
||||||
|
|
||||||
std::cout << "fatal_error: " << msg;
|
std::cout << "fatal_error: " << msg;
|
||||||
std::cout << ": " << std::hex << tagged << std::dec;
|
std::cout << ": " << (void*)tagged;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
exit(1);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void critical_error(const char *msg, cell tagged)
|
void critical_error(const char *msg, cell tagged)
|
||||||
|
@ -59,7 +73,9 @@ void factor_vm::general_error(vm_error_type error, cell arg1, cell arg2)
|
||||||
|
|
||||||
ctx->push(error_object);
|
ctx->push(error_object);
|
||||||
|
|
||||||
faulting_p = false;
|
/* Guard the safepoint, which will clear faulting_p if unwind-native-frames
|
||||||
|
succeeds */
|
||||||
|
code->guard_safepoint();
|
||||||
unwind_native_frames(special_objects[ERROR_HANDLER_QUOT],
|
unwind_native_frames(special_objects[ERROR_HANDLER_QUOT],
|
||||||
ctx->callstack_top);
|
ctx->callstack_top);
|
||||||
}
|
}
|
||||||
|
@ -71,8 +87,8 @@ void factor_vm::general_error(vm_error_type error, cell arg1, cell arg2)
|
||||||
std::cout << "error: " << error << std::endl;
|
std::cout << "error: " << error << std::endl;
|
||||||
std::cout << "arg 1: "; print_obj(arg1); std::cout << std::endl;
|
std::cout << "arg 1: "; print_obj(arg1); std::cout << std::endl;
|
||||||
std::cout << "arg 2: "; print_obj(arg2); std::cout << std::endl;
|
std::cout << "arg 2: "; print_obj(arg2); std::cout << std::endl;
|
||||||
faulting_p = false;
|
|
||||||
factorbug();
|
factorbug();
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,12 +102,24 @@ void factor_vm::not_implemented_error()
|
||||||
general_error(ERROR_NOT_IMPLEMENTED,false_object,false_object);
|
general_error(ERROR_NOT_IMPLEMENTED,false_object,false_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void factor_vm::verify_memory_protection_error(cell addr)
|
||||||
|
{
|
||||||
|
/* Called from the OS-specific top halves of the signal handlers to
|
||||||
|
make sure it's safe to dispatch to memory_protection_error */
|
||||||
|
if(fatal_erroring_p)
|
||||||
|
fa_diddly_atal_error();
|
||||||
|
if(faulting_p && !code->safepoint_p(addr))
|
||||||
|
fatal_error("Double fault", addr);
|
||||||
|
else if(fep_p)
|
||||||
|
fatal_error("Memory protection fault during low-level debugger", addr);
|
||||||
|
else if(atomic::load(¤t_gc_p))
|
||||||
|
fatal_error("Memory protection fault during gc", addr);
|
||||||
|
}
|
||||||
|
|
||||||
void factor_vm::memory_protection_error(cell addr)
|
void factor_vm::memory_protection_error(cell addr)
|
||||||
{
|
{
|
||||||
if(code->safepoint_p(addr))
|
if(code->safepoint_p(addr))
|
||||||
safepoint.handle_safepoint(this);
|
safepoint.handle_safepoint(this);
|
||||||
else if(faulting_p)
|
|
||||||
fatal_error("Double fault", 0);
|
|
||||||
else if(ctx->datastack_seg->underflow_p(addr))
|
else if(ctx->datastack_seg->underflow_p(addr))
|
||||||
general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
|
general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
|
||||||
else if(ctx->datastack_seg->overflow_p(addr))
|
else if(ctx->datastack_seg->overflow_p(addr))
|
||||||
|
|
|
@ -40,6 +40,7 @@ void factor_vm::call_fault_handler(
|
||||||
if(exception == EXC_BAD_ACCESS)
|
if(exception == EXC_BAD_ACCESS)
|
||||||
{
|
{
|
||||||
signal_fault_addr = MACH_EXC_STATE_FAULT(exc_state);
|
signal_fault_addr = MACH_EXC_STATE_FAULT(exc_state);
|
||||||
|
verify_memory_protection_error(signal_fault_addr);
|
||||||
handler = (cell)factor::memory_signal_handler_impl;
|
handler = (cell)factor::memory_signal_handler_impl;
|
||||||
}
|
}
|
||||||
else if(exception == EXC_ARITHMETIC && code != MACH_EXC_INTEGER_DIV)
|
else if(exception == EXC_ARITHMETIC && code != MACH_EXC_INTEGER_DIV)
|
||||||
|
|
|
@ -165,18 +165,23 @@ void factor_vm::end_sampling_profiler_timer()
|
||||||
void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||||
{
|
{
|
||||||
factor_vm *vm = current_vm();
|
factor_vm *vm = current_vm();
|
||||||
|
vm->verify_memory_protection_error((cell)siginfo->si_addr);
|
||||||
vm->signal_fault_addr = (cell)siginfo->si_addr;
|
vm->signal_fault_addr = (cell)siginfo->si_addr;
|
||||||
vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
|
vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void synchronous_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
void synchronous_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||||
{
|
{
|
||||||
|
if (factor_vm::fatal_erroring_p)
|
||||||
|
return;
|
||||||
|
|
||||||
factor_vm *vm = current_vm_p();
|
factor_vm *vm = current_vm_p();
|
||||||
if (vm)
|
if (vm)
|
||||||
{
|
{
|
||||||
vm->signal_number = signal;
|
vm->signal_number = signal;
|
||||||
vm->dispatch_signal(uap,factor::synchronous_signal_handler_impl);
|
vm->dispatch_signal(uap,factor::synchronous_signal_handler_impl);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
fatal_error("Foreign thread received signal", signal);
|
fatal_error("Foreign thread received signal", signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +195,9 @@ static void enqueue_signal(factor_vm *vm, int signal)
|
||||||
|
|
||||||
void enqueue_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
void enqueue_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||||
{
|
{
|
||||||
|
if (factor_vm::fatal_erroring_p)
|
||||||
|
return;
|
||||||
|
|
||||||
factor_vm *vm = current_vm_p();
|
factor_vm *vm = current_vm_p();
|
||||||
if (vm)
|
if (vm)
|
||||||
enqueue_signal(vm, signal);
|
enqueue_signal(vm, signal);
|
||||||
|
@ -199,6 +207,9 @@ void enqueue_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||||
|
|
||||||
void fep_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
void fep_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||||
{
|
{
|
||||||
|
if (factor_vm::fatal_erroring_p)
|
||||||
|
return;
|
||||||
|
|
||||||
factor_vm *vm = current_vm_p();
|
factor_vm *vm = current_vm_p();
|
||||||
if (vm)
|
if (vm)
|
||||||
{
|
{
|
||||||
|
@ -251,7 +262,7 @@ static void sigaction_safe(int signum, const struct sigaction *act, struct sigac
|
||||||
while(ret == -1 && errno == EINTR);
|
while(ret == -1 && errno == EINTR);
|
||||||
|
|
||||||
if(ret == -1)
|
if(ret == -1)
|
||||||
fatal_error("sigaction failed", 0);
|
fatal_error("sigaction failed", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_sigaction_with_handler(struct sigaction *act,
|
static void init_sigaction_with_handler(struct sigaction *act,
|
||||||
|
@ -499,4 +510,16 @@ void factor_vm::unlock_console()
|
||||||
pthread_mutex_unlock(&stdin_mutex);
|
pthread_mutex_unlock(&stdin_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void factor_vm::abort()
|
||||||
|
{
|
||||||
|
sig_t ret;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = signal(SIGABRT, SIG_DFL);
|
||||||
|
}
|
||||||
|
while(ret == SIG_ERR && errno == EINTR);
|
||||||
|
|
||||||
|
::abort();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,4 +45,9 @@ void sleep_nanos(u64 nsec);
|
||||||
|
|
||||||
void move_file(const vm_char *path1, const vm_char *path2);
|
void move_file(const vm_char *path1, const vm_char *path2);
|
||||||
|
|
||||||
|
static inline void breakpoint()
|
||||||
|
{
|
||||||
|
__builtin_trap();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,12 +214,21 @@ void sleep_nanos(u64 nsec)
|
||||||
Sleep((DWORD)(nsec/1000000));
|
Sleep((DWORD)(nsec/1000000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum _EXCEPTION_DISPOSITION
|
||||||
|
{
|
||||||
|
ExceptionContinueExecution = 0,
|
||||||
|
ExceptionContinueSearch = 1,
|
||||||
|
ExceptionNestedException = 2,
|
||||||
|
ExceptionCollidedUnwind = 3
|
||||||
|
} EXCEPTION_DISPOSITION;
|
||||||
|
|
||||||
LONG factor_vm::exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
|
LONG factor_vm::exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
|
||||||
{
|
{
|
||||||
switch (e->ExceptionCode)
|
switch (e->ExceptionCode)
|
||||||
{
|
{
|
||||||
case EXCEPTION_ACCESS_VIOLATION:
|
case EXCEPTION_ACCESS_VIOLATION:
|
||||||
signal_fault_addr = e->ExceptionInformation[1];
|
signal_fault_addr = e->ExceptionInformation[1];
|
||||||
|
verify_memory_protection_error(signal_fault_addr);
|
||||||
dispatch_signal_handler(
|
dispatch_signal_handler(
|
||||||
(cell*)&c->ESP,
|
(cell*)&c->ESP,
|
||||||
(cell*)&c->EIP,
|
(cell*)&c->EIP,
|
||||||
|
@ -261,19 +270,19 @@ LONG factor_vm::exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ExceptionContinueExecution;
|
||||||
}
|
}
|
||||||
|
|
||||||
VM_C_API LONG exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
|
VM_C_API LONG exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
|
||||||
{
|
{
|
||||||
|
if (factor_vm::fatal_erroring_p)
|
||||||
|
return ExceptionContinueSearch;
|
||||||
|
|
||||||
factor_vm *vm = current_vm_p();
|
factor_vm *vm = current_vm_p();
|
||||||
if (vm)
|
if (vm)
|
||||||
return vm->exception_handler(e,frame,c,dispatch);
|
return vm->exception_handler(e,frame,c,dispatch);
|
||||||
else
|
else
|
||||||
{
|
return ExceptionContinueSearch;
|
||||||
fatal_error("Foreign thread received exception", e->ExceptionCode);
|
|
||||||
return 0; // to placate MSVC
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
|
static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
|
||||||
|
@ -380,4 +389,9 @@ void factor_vm::end_sampling_profiler_timer()
|
||||||
sampler_thread = NULL;
|
sampler_thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void factor_vm::abort()
|
||||||
|
{
|
||||||
|
::abort();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,11 @@ inline static THREADHANDLE thread_id()
|
||||||
return threadHandle;
|
return threadHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static breakpoint()
|
||||||
|
{
|
||||||
|
DebugBreak();
|
||||||
|
}
|
||||||
|
|
||||||
#define CODE_TO_FUNCTION_POINTER(code) (void)0
|
#define CODE_TO_FUNCTION_POINTER(code) (void)0
|
||||||
#define CODE_TO_FUNCTION_POINTER_CALLBACK(vm, code) (void)0
|
#define CODE_TO_FUNCTION_POINTER_CALLBACK(vm, code) (void)0
|
||||||
#define FUNCTION_CODE_POINTER(ptr) ptr
|
#define FUNCTION_CODE_POINTER(ptr) ptr
|
||||||
|
|
|
@ -38,6 +38,7 @@ void safepoint_state::enqueue_samples(factor_vm *parent, cell samples, cell pc,
|
||||||
void safepoint_state::handle_safepoint(factor_vm *parent) volatile
|
void safepoint_state::handle_safepoint(factor_vm *parent) volatile
|
||||||
{
|
{
|
||||||
parent->code->unguard_safepoint();
|
parent->code->unguard_safepoint();
|
||||||
|
parent->faulting_p = false;
|
||||||
|
|
||||||
if (atomic::load(&fep_p))
|
if (atomic::load(&fep_p))
|
||||||
{
|
{
|
||||||
|
|
|
@ -143,6 +143,7 @@ struct factor_vm
|
||||||
|
|
||||||
/* Are we already handling a fault? Used to catch double memory faults */
|
/* Are we already handling a fault? Used to catch double memory faults */
|
||||||
bool faulting_p;
|
bool faulting_p;
|
||||||
|
static bool fatal_erroring_p;
|
||||||
|
|
||||||
/* Safepoint state */
|
/* Safepoint state */
|
||||||
volatile safepoint_state safepoint;
|
volatile safepoint_state safepoint;
|
||||||
|
@ -213,6 +214,7 @@ struct factor_vm
|
||||||
void general_error(vm_error_type error, cell arg1, cell arg2);
|
void general_error(vm_error_type error, cell arg1, cell arg2);
|
||||||
void type_error(cell type, cell tagged);
|
void type_error(cell type, cell tagged);
|
||||||
void not_implemented_error();
|
void not_implemented_error();
|
||||||
|
void verify_memory_protection_error(cell addr);
|
||||||
void memory_protection_error(cell addr);
|
void memory_protection_error(cell addr);
|
||||||
void signal_error(cell signal);
|
void signal_error(cell signal);
|
||||||
void divide_by_zero_error();
|
void divide_by_zero_error();
|
||||||
|
@ -730,6 +732,7 @@ struct factor_vm
|
||||||
void open_console();
|
void open_console();
|
||||||
void lock_console();
|
void lock_console();
|
||||||
void unlock_console();
|
void unlock_console();
|
||||||
|
static void abort();
|
||||||
|
|
||||||
// os-windows
|
// os-windows
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
|
Loading…
Reference in New Issue