summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Leroy <xavierleroy@users.noreply.github.com>2021-03-05 19:14:07 +0100
committerDavid Allsopp <david.allsopp@metastack.com>2022-01-17 11:16:15 +0000
commitd111407bf4ff71171598d30825c8e59ed5f75fd6 (patch)
treed0a126fd2a3f95c5bdb369bad46d5d1fcfd02fdf
parentecc80c0d3850bc144760af4c63b7eab438615bdc (diff)
downloadocaml-d111407bf4ff71171598d30825c8e59ed5f75fd6.tar.gz
Dynamically allocate the alternate signal stack
In Glibc 2.34 and later, SIGSTKSZ may not be a compile-time constant. It is no longer possible to statically allocate the alternate signal stack for the main thread, as we've been doing for the last 25 years. This commit implements dynamic allocation of the alternate signal stack even for the main thread. It reuses the code already in place to allocate the alternate signal stack for other threads. The alternate signal stack is freed when the main OCaml code / an OCaml thread stops. (partial back-port of PR#10266 and PR#10726)
-rw-r--r--asmrun/fail.c7
-rw-r--r--asmrun/signals_asm.c64
-rw-r--r--asmrun/startup.c3
-rw-r--r--byterun/sys.c4
4 files changed, 68 insertions, 10 deletions
diff --git a/asmrun/fail.c b/asmrun/fail.c
index 09a9af9668..9d3f0f75ee 100644
--- a/asmrun/fail.c
+++ b/asmrun/fail.c
@@ -25,6 +25,8 @@
#include "stack.h"
#include "roots.h"
+extern void caml_terminate_signals(void);
+
/* The globals holding predefined exceptions */
typedef value caml_generated_constant[1];
@@ -55,7 +57,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 4f62bd38a9..34365aa7dc 100644
--- a/asmrun/signals_asm.c
+++ b/asmrun/signals_asm.c
@@ -179,7 +179,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
@@ -272,17 +271,64 @@ 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_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
+
+#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 1ccd4eca94..532f1f9169 100644
--- a/asmrun/startup.c
+++ b/asmrun/startup.c
@@ -146,6 +146,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);
#ifdef _MSC_VER
@@ -191,10 +192,12 @@ void caml_main(char **argv)
#endif
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;
}
res = caml_start_program();
+ caml_terminate_signals();
if (Is_exception_result(res))
caml_fatal_uncaught_exception(Extract_exception(res));
}
diff --git a/byterun/sys.c b/byterun/sys.c
index 8b2551a004..99ea0f55b3 100644
--- a/byterun/sys.c
+++ b/byterun/sys.c
@@ -91,10 +91,14 @@ CAMLexport void caml_sys_io_error(value arg)
}
}
+extern void caml_terminate_signals(void);
+
CAMLprim value caml_sys_exit(value retcode)
{
#ifndef NATIVE_CODE
caml_debugger(PROGRAM_EXIT);
+#else
+ caml_terminate_signals();
#endif
exit(Int_val(retcode));
return Val_unit;