Blob Blame History Raw
From 24a9db7784ddfcf0af2d2be2f51616ed960ae7e8 Mon Sep 17 00:00:00 2001
From: Xavier Leroy <xavierleroy@users.noreply.github.com>
Date: Fri, 5 Mar 2021 19:14:07 +0100
Subject: [PATCH 6/6] Dynamically allocate the alternate signal stack (#10266)

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.

Fixes: #10250.
(cherry picked from commit fc9534746bf5d08a4c109f22e344cf49d5d46d54)
---
 runtime/caml/signals.h |  2 +-
 runtime/signals_byt.c  |  2 +-
 runtime/signals_nat.c  | 25 ++++++++++++++-----------
 3 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/runtime/caml/signals.h b/runtime/caml/signals.h
index 7ec1ad3ba..98b75107b 100644
--- a/runtime/caml/signals.h
+++ b/runtime/caml/signals.h
@@ -82,7 +82,7 @@ void caml_set_action_pending (void);
 value caml_do_pending_actions_exn (void);
 value caml_process_pending_actions_with_root (value extra_root); // raises
 int caml_set_signal_action(int signo, int action);
-void caml_setup_stack_overflow_detection(void);
+CAMLextern int caml_setup_stack_overflow_detection(void);
 
 CAMLextern void (*caml_enter_blocking_section_hook)(void);
 CAMLextern void (*caml_leave_blocking_section_hook)(void);
diff --git a/runtime/signals_byt.c b/runtime/signals_byt.c
index 040de03c5..9bd2b20c6 100644
--- a/runtime/signals_byt.c
+++ b/runtime/signals_byt.c
@@ -86,4 +86,4 @@ int caml_set_signal_action(int signo, int action)
     return 0;
 }
 
-void caml_setup_stack_overflow_detection(void) {}
+CAMLexport int caml_setup_stack_overflow_detection(void) { return 0; }
diff --git a/runtime/signals_nat.c b/runtime/signals_nat.c
index fc5a77f84..f56fce6b7 100644
--- a/runtime/signals_nat.c
+++ b/runtime/signals_nat.c
@@ -195,8 +195,6 @@ DECLARE_SIGNAL_HANDLER(trap_handler)
 #error "CONTEXT_SP is required if HAS_STACK_OVERFLOW_DETECTION is defined"
 #endif
 
-static char sig_alt_stack[SIGSTKSZ];
-
 /* Code compiled with ocamlopt never accesses more than
    EXTRA_STACK bytes below the stack pointer. */
 #define EXTRA_STACK 256
@@ -282,28 +280,33 @@ void caml_init_signals(void)
 #endif
 
 #ifdef HAS_STACK_OVERFLOW_DETECTION
-  {
-    stack_t stk;
+  if (caml_setup_stack_overflow_detection() != -1) {
     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);
-    if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }
+    sigaction(SIGSEGV, &act, NULL);
   }
 #endif
 }
 
-void caml_setup_stack_overflow_detection(void)
+/* Allocate and select an alternate stack for handling signals,
+   especially SIGSEGV signals.
+   Each thread needs its own alternate stack.
+   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 (issue #10250). */
+
+CAMLexport int caml_setup_stack_overflow_detection(void)
 {
 #ifdef HAS_STACK_OVERFLOW_DETECTION
   stack_t stk;
   stk.ss_sp = malloc(SIGSTKSZ);
+  if (stk.ss_sp == NULL) return -1;
   stk.ss_size = SIGSTKSZ;
   stk.ss_flags = 0;
-  if (stk.ss_sp)
-    sigaltstack(&stk, NULL);
+  return sigaltstack(&stk, NULL);
+#else
+  return 0;
 #endif
 }
-- 
2.32.0