From c184ca2c68abfc6864c7fc64d7b3c3e657afd7a8 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 18 Aug 2026 17:50:28 +0200 Subject: [PATCH 1/2] fix(lifecycle): ignore signals during os_exit Problem: SIGTERM received during `os_exit()` can cause it to "nest": os_exit src/nvim/main.c:720 preserve_exit src/nvim/main.c:910 deadly_signal src/nvim/os/signal.c:205 on_signal src/nvim/os/signal.c:240 signal_event src/nvim/event/signal.c:45 multiqueue_process_events src/nvim/event/multiqueue.c:159 event_teardown src/nvim/main.c:178 os_exit src/nvim/main.c:720 Solution: Call `signal_reject_deadly()` at the start of `os_exit()` like `preserve_exit()` already does. --- src/nvim/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nvim/main.c b/src/nvim/main.c index 467d9ddb54..b87f32fb90 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -706,6 +706,8 @@ void os_exit(int r) FUNC_ATTR_NORETURN { exiting = true; + // Avoid recursion in case SIGTERM arrives during `os_exit`. + signal_reject_deadly(); if (ui_client_channel_id) { ui_client_stop(); From 73e766f8f6ec248bd2bf023af32ef45f40d05d39 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 18 Aug 2026 21:30:05 +0200 Subject: [PATCH 2/2] fix(lifecycle): json_create_config leak Problem: As it turns out, when you have 17 different ways to "exit", you need to plug 17 different holes. Leak still reported by ASAN CI, even after 1eae512285e7 f238788601eb. ERROR: LeakSanitizer: detected memory leaks strbuf_init src/cjson/strbuf.c:62:22 json_create_config src/cjson/lua_cjson.c:635:5 lua_cjson_new src/cjson/lua_cjson.c:2060:5 nlua_state_add_stdlib src/nvim/lua/stdlib.c:840:3 nlua_state_init src/nvim/lua/executor.c:973:3 Analysis: `os_breakcheck()` may process a `exit_event` placed by `exit_on_closed_chan()` during shutdown. This would re-enter `preserve_exit()`, which then skips everything because it sees `really_exiting=true`. Solution: Set `exiting` in `preserve_exit()`, not only in `getout()`. --- src/nvim/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nvim/main.c b/src/nvim/main.c index b87f32fb90..0e3ed4ed5e 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -897,6 +897,8 @@ void preserve_exit(const char *errmsg) } really_exiting = true; + // Set this now, to neuter a stray `exit_event` on the event-loop. #39675 + exiting = true; // Ignore SIGHUP while we are already exiting. #9274 signal_reject_deadly();