Index: vm/port/src/signals/linux/signals_common.cpp =================================================================== --- vm/port/src/signals/linux/signals_common.cpp (revision 663349) +++ vm/port/src/signals/linux/signals_common.cpp (working copy) @@ -63,7 +63,11 @@ { case SIGSEGV: if (tlsdata->restore_guard_page) + { + // Now it's safe to disable alternative stack + set_alt_stack(tlsdata, FALSE); result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, FALSE); + } else result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE); break; @@ -222,6 +226,9 @@ else { // To process signal on protected stack area port_thread_clear_guard_page(); + // Note: the call above does not disable alternative stack + // It can't be made while we are on alternative stack + // Alt stack will be disabled explicitly in c_handler() tlsdata->restore_guard_page = TRUE; } } Index: vm/port/src/thread/linux/thread_os.c =================================================================== --- vm/port/src/thread/linux/thread_os.c (revision 663349) +++ vm/port/src/thread/linux/thread_os.c (working copy) @@ -203,10 +203,24 @@ return res; } +int set_alt_stack(port_tls_data_t* tlsdata, Boolean set) +{ + stack_t sigalt; + + // sets alternative stack + sigalt.ss_sp = tlsdata->guard_stack_addr; + sigalt.ss_size = tlsdata->guard_stack_size; +//#if defined(FREEBSD) + sigalt.ss_flags = set ? 0 : SS_DISABLE; +//#else +// sigalt.ss_flags = set ? SS_ONSTACK : SS_DISABLE; +//#endif + return sigaltstack(&sigalt, NULL); +} + static int set_guard_page(port_tls_data_t* tlsdata, Boolean set) { int res; - stack_t sigalt; if (!tlsdata) tlsdata = get_private_tls_data(); @@ -218,7 +232,7 @@ return 0; if ((set && tlsdata->guard_page_set) || - !set && !tlsdata->guard_page_set) + (!set && !tlsdata->guard_page_set)) return 0; // Already in needed state res = mprotect(tlsdata->guard_page_addr, tlsdata->guard_page_size, @@ -227,18 +241,13 @@ if (res != 0) return errno; - // sets alternative stack - sigalt.ss_sp = tlsdata->guard_stack_addr; - sigalt.ss_size = tlsdata->guard_stack_size; -//#if defined(FREEBSD) - sigalt.ss_flags = set ? 0 : SS_DISABLE; -//#else -// sigalt.ss_flags = set ? SS_ONSTACK : SS_DISABLE; -//#endif - res = sigaltstack(&sigalt, NULL); + if (set) + { + res = set_alt_stack(tlsdata, TRUE); - if (res != 0) - return errno; + if (res != 0) + return errno; + } tlsdata->guard_page_set = set; return 0; Index: vm/port/src/thread/include/port_thread_internal.h =================================================================== --- vm/port/src/thread/include/port_thread_internal.h (revision 663349) +++ vm/port/src/thread/include/port_thread_internal.h (working copy) @@ -159,7 +159,13 @@ /* Detaches temporarily attached thread */ int port_thread_detach_temporary(); +#ifndef WIN32 +/* To restore alternative stack out of signal handler on Linux */ +int set_alt_stack(port_tls_data_t* tlsdata, Boolean set); +#endif + + #ifdef __cplusplus } #endif