diff options
Diffstat (limited to 'asmrun')
-rw-r--r-- | asmrun/fail.c | 7 | ||||
-rw-r--r-- | asmrun/signals_asm.c | 69 | ||||
-rw-r--r-- | asmrun/startup.c | 7 |
3 files changed, 72 insertions, 11 deletions
diff --git a/asmrun/fail.c b/asmrun/fail.c index d73cb88524..2f06432018 100644 --- a/asmrun/fail.c +++ b/asmrun/fail.c @@ -31,6 +31,8 @@ #include "caml/roots.h" #include "caml/callback.h" +extern void caml_terminate_signals(void); + /* The globals holding predefined exceptions */ typedef value caml_generated_constant[1]; @@ -60,7 +62,10 @@ char * caml_exception_pointer = NULL; void caml_raise(value v) { Unlock_exn(); - if (caml_exception_pointer == NULL) caml_fatal_uncaught_exception(v); + if (caml_exception_pointer == NULL) { + caml_terminate_signals(); + caml_fatal_uncaught_exception(v); + } #ifndef Stack_grows_upwards #define PUSHED_AFTER < diff --git a/asmrun/signals_asm.c b/asmrun/signals_asm.c index f124a07674..b4e2516ae1 100644 --- a/asmrun/signals_asm.c +++ b/asmrun/signals_asm.c @@ -194,7 +194,6 @@ DECLARE_SIGNAL_HANDLER(trap_handler) #ifdef HAS_STACK_OVERFLOW_DETECTION static char * system_stack_top; -static char sig_alt_stack[SIGSTKSZ]; #if defined(SYS_linux) /* PR#4746: recent Linux kernels with support for stack randomization @@ -295,17 +294,69 @@ void caml_init_signals(void) { stack_t stk; struct sigaction act; - stk.ss_sp = sig_alt_stack; - stk.ss_size = SIGSTKSZ; - stk.ss_flags = 0; - SET_SIGACT(act, segv_handler); - act.sa_flags |= SA_ONSTACK | SA_NODEFER; - sigemptyset(&act.sa_mask); - system_stack_top = (char *) &act; - if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); } + /* Allocate and select an alternate stack for handling signals, + especially SIGSEGV signals. + The alternate stack used to be statically-allocated for the main thread, + but this is incompatible with Glibc 2.34 and newer, where SIGSTKSZ + may not be a compile-time constant. */ + stk.ss_sp = malloc(SIGSTKSZ); + if (stk.ss_sp != NULL) { + stk.ss_size = SIGSTKSZ; + stk.ss_flags = 0; + SET_SIGACT(act, segv_handler); + act.sa_flags |= SA_ONSTACK | SA_NODEFER; + sigemptyset(&act.sa_mask); + system_stack_top = (char *) &act; + if (sigaltstack(&stk, NULL) == 0) + sigaction(SIGSEGV, &act, NULL); + else + free(stk.ss_sp); + } } #endif #if defined(_WIN32) && !defined(_WIN64) caml_win32_overflow_detection(); #endif } + +/* Termination of signal stuff */ + +#if defined(TARGET_power) || defined(TARGET_s390x) \ + || defined(TARGET_sparc) && defined(SYS_solaris) \ + || defined(HAS_STACK_OVERFLOW_DETECTION) +static void set_signal_default(int signum) +{ + struct sigaction act; + sigemptyset(&act.sa_mask); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigaction(signum, &act, NULL); +} +#endif + +void caml_terminate_signals(void) +{ +#if defined(TARGET_sparc) && defined(SYS_solaris) + set_signal_default(SIGILL); +#endif + +#if defined(TARGET_power) + set_signal_default(SIGTRAP); +#endif + +#if defined(TARGET_s390x) + set_signal_default(SIGFPE); +#endif + +#ifdef HAS_STACK_OVERFLOW_DETECTION + set_signal_default(SIGSEGV); + stack_t oldstk, stk; + stk.ss_flags = SS_DISABLE; + if (sigaltstack(&stk, &oldstk) == 0) { + /* If caml_init_signals failed, we are not using an alternate signal stack. + SS_DISABLE will be set in oldstk, and there is nothing to free in this + case. */ + if (! (oldstk.ss_flags & SS_DISABLE)) free(oldstk.ss_sp); + } +#endif +} diff --git a/asmrun/startup.c b/asmrun/startup.c index 70bbc4369d..a1cb06a7d1 100644 --- a/asmrun/startup.c +++ b/asmrun/startup.c @@ -92,6 +92,7 @@ void (*caml_termination_hook)(void *) = NULL; extern value caml_start_program (void); extern void caml_init_ieee_floats (void); extern void caml_init_signals (void); +extern void caml_terminate_signals(void); #if defined(_MSC_VER) && __STDC_SECURE_LIB__ >= 200411L @@ -103,6 +104,7 @@ extern void caml_install_invalid_parameter_handler(); value caml_startup_exn(char **argv) { char * exe_name, * proc_self_exe; + value res; char tos; #ifdef WITH_SPACETIME @@ -138,10 +140,13 @@ value caml_startup_exn(char **argv) exe_name = caml_search_exe_in_path(exe_name); caml_sys_init(exe_name, argv); if (sigsetjmp(caml_termination_jmpbuf.buf, 0)) { + caml_terminate_signals(); if (caml_termination_hook != NULL) caml_termination_hook(NULL); return Val_unit; } - return caml_start_program(); + res = caml_start_program(); + caml_terminate_signals(); + return res; } void caml_startup(char **argv) |