commit 47416641591997ccc7327528e9c972571436b9bc
parent a2abf09a805ee4916fbcdd926a9d444cbc34229d
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 11 May 2026 14:17:17 -0700
dbg: copy CfreeDbgSignalOps in signals_install, not the caller pointer
The signal handler dereferenced g_dbg_ops, which pointed at a stack-local
in cfree_jit_session_new. By the time the worker took its first BRK that
frame was gone, so the handler jumped to garbage and the REPL hung
waiting on ev_stop (or surfaced as Trace/BPT trap: 5).
Diffstat:
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/driver/env.c b/driver/env.c
@@ -452,7 +452,8 @@ static CfreeExecMem g_execmem_posix; /* page_size set in driver_env_init */
* handler reads these from async-signal context; both writes happen in
* signals_install before any signal can arrive, both clears happen in
* signals_uninstall after restoring SIG_DFL. */
-static const CfreeDbgSignalOps* g_dbg_ops;
+static CfreeDbgSignalOps g_dbg_ops;
+static int g_dbg_ops_set;
static void* g_dbg_session;
static pthread_t g_dbg_worker_tid;
static int g_dbg_worker_tid_valid;
@@ -643,8 +644,8 @@ static void dbg_signal_handler(int signo, siginfo_t* si, void* ucv) {
/* Only the registered worker thread participates in stop-the-world.
* Faults on other threads (e.g. the REPL) fall through to the default. */
if (!g_dbg_worker_tid_valid ||
- !pthread_equal(pthread_self(), g_dbg_worker_tid) || !g_dbg_ops ||
- !g_dbg_ops->on_fault) {
+ !pthread_equal(pthread_self(), g_dbg_worker_tid) || !g_dbg_ops_set ||
+ !g_dbg_ops.on_fault) {
int i;
for (i = 0; i < DBG_NSIGS; ++i) {
if (g_dbg_signos[i] == signo) {
@@ -657,7 +658,7 @@ static void dbg_signal_handler(int signo, siginfo_t* si, void* ucv) {
}
dbg_ucontext_to_frame(uc, &frame);
- rc = g_dbg_ops->on_fault(g_dbg_session, signo, &frame);
+ rc = g_dbg_ops.on_fault(g_dbg_session, signo, &frame);
if (rc != 0) {
/* Session declined to handle: restore default and re-raise so the
* host produces a core dump for the original cause. */
@@ -680,7 +681,8 @@ static int dbg_signals_install(void* user, const CfreeDbgSignalOps* ops,
int i;
(void)user;
if (g_dbg_installed) return 1;
- g_dbg_ops = ops;
+ g_dbg_ops = *ops;
+ g_dbg_ops_set = 1;
g_dbg_session = session;
memset(&sa, 0, sizeof(sa));
@@ -696,7 +698,8 @@ static int dbg_signals_install(void* user, const CfreeDbgSignalOps* ops,
/* Roll back what we installed. */
int j;
for (j = 0; j < i; ++j) sigaction(g_dbg_signos[j], &g_dbg_prev_sa[j], NULL);
- g_dbg_ops = NULL;
+ memset(&g_dbg_ops, 0, sizeof(g_dbg_ops));
+ g_dbg_ops_set = 0;
g_dbg_session = NULL;
return 1;
}
@@ -712,7 +715,8 @@ static void dbg_signals_uninstall(void* user) {
for (i = 0; i < DBG_NSIGS; ++i)
sigaction(g_dbg_signos[i], &g_dbg_prev_sa[i], NULL);
g_dbg_installed = 0;
- g_dbg_ops = NULL;
+ memset(&g_dbg_ops, 0, sizeof(g_dbg_ops));
+ g_dbg_ops_set = 0;
g_dbg_session = NULL;
}