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:15:41 +0000
commit50c2d1275e537906ea144bd557fde31e0bf16e5f (patch)
tree92a3e8350c7edabce1078efe4b2a0a3552eaf9cd
parentc684ef1cb76d67a59dbf395040303b26fc5b7931 (diff)
downloadocaml-50c2d1275e537906ea144bd557fde31e0bf16e5f.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.c69
-rw-r--r--asmrun/startup.c7
-rw-r--r--byterun/sys.c5
4 files changed, 77 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)
diff --git a/byterun/sys.c b/byterun/sys.c
index 3706e9002d..aa152239eb 100644
--- a/byterun/sys.c
+++ b/byterun/sys.c
@@ -111,6 +111,8 @@ static void caml_sys_check_path(value name)
}
}
+extern void caml_terminate_signals(void);
+
CAMLprim value caml_sys_exit(value retcode_v)
{
int retcode = Int_val(retcode_v);
@@ -144,6 +146,9 @@ CAMLprim value caml_sys_exit(value retcode_v)
caml_debugger(PROGRAM_EXIT);
#endif
CAML_INSTR_ATEXIT ();
+#ifdef NATIVE_CODE
+ caml_terminate_signals();
+#endif
CAML_SYS_EXIT(retcode);
return Val_unit;
}