nandi/cosmicnimpublic Fork 0
fcee0b9
Commits
Clone
git clone https://git.rickub.com/nandi/cosmicnim.git
git clone ssh://git@rickub.com/nandi/cosmicnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Stop Nim's signal handler from crashing on libcosmic's threads

The gallery segfaulted with a stack of signalHandler -> rawNewString ->
rawAlloc on a thread named "notify-rs inoti". Nim installs its signal
handlers process-wide and they allocate to build a traceback, so a signal
landing on a thread libcosmic created — a tokio worker, or the inotify
watcher — faults inside the handler, and the resulting core points at the
allocator rather than at whatever actually happened.

Reproduced it with tgkill against that exact thread: default build dies
with SIGSEGV, -d:noSignalHandler takes the default action and exits
cleanly. examples/nim.cfg sets the flag, and the binding warns when a
host forgets it, since this bites any program that loads the library.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-20T10:52:58-07:00 Browse files
fcee0b9 parent: 6992433
modified README.md +13 -0
@@ -72,6 +72,19 @@ v0.2.0 release and no other, so a stale library cannot load against newer
7272 bindings. `just fetch v0.1.2` (or `COSMICNIM_TAG=v0.1.2 nimble fetchLib`)
7373 overrides that when you want it.
7474
75+## Signal handling
76+
77+Compile anything that loads this library with `-d:noSignalHandler`
78+(`examples/nim.cfg` does it for the demo, and the binding warns if you
79+forget).
80+
81+libcosmic creates threads Nim knows nothing about — tokio workers and a
82+`notify-rs` inotify watcher. Nim installs its signal handlers process-wide,
83+and the handler allocates a string to build a traceback, so a signal
84+delivered to one of those threads faults inside the handler. The crash it
85+produces points at `rawAlloc`, which tells you nothing about the real
86+cause; the handler has already destroyed that evidence.
87+
7588 ## As a dependency
7689
7790 ```bash
@@ -72,6 +72,19 @@ v0.2.0 release and no other, so a stale library cannot load against newer
72 bindings. `just fetch v0.1.2` (or `COSMICNIM_TAG=v0.1.2 nimble fetchLib`)72 bindings. `just fetch v0.1.2` (or `COSMICNIM_TAG=v0.1.2 nimble fetchLib`)
73 overrides that when you want it.73 overrides that when you want it.
74 74
75+## Signal handling
76+
77+Compile anything that loads this library with `-d:noSignalHandler`
78+(`examples/nim.cfg` does it for the demo, and the binding warns if you
79+forget).
80+
81+libcosmic creates threads Nim knows nothing about — tokio workers and a
82+`notify-rs` inotify watcher. Nim installs its signal handlers process-wide,
83+and the handler allocates a string to build a traceback, so a signal
84+delivered to one of those threads faults inside the handler. The crash it
85+produces points at `rawAlloc`, which tells you nothing about the real
86+cause; the handler has already destroyed that evidence.
87+
75 ## As a dependency88 ## As a dependency
76 89
77 ```bash90 ```bash
added examples/nim.cfg +6 -0
new file mode 100644
@@ -0,0 +1,6 @@
1+# libcosmic creates threads Nim knows nothing about (tokio workers, the
2+# notify-rs inotify watcher). Nim's signal handlers are installed process-wide
3+# and allocate a string to build a traceback, so a signal delivered to one of
4+# those threads segfaults inside the handler itself. Let the default action
5+# stand instead.
6+-d:noSignalHandler
new file mode 100644
@@ -0,0 +1,6 @@
1+# libcosmic creates threads Nim knows nothing about (tokio workers, the
2+# notify-rs inotify watcher). Nim's signal handlers are installed process-wide
3+# and allocate a string to build a traceback, so a signal delivered to one of
4+# those threads segfaults inside the handler itself. Let the default action
5+# stand instead.
6+-d:noSignalHandler
modified nim/cosmicnim.nim +5 -0
@@ -16,6 +16,11 @@
1616
1717 import std/os
1818
19+when not defined(noSignalHandler):
20+ {.warning: "compile with -d:noSignalHandler: libcosmic runs threads Nim " &
21+ "did not create, and Nim's signal handler allocates, so a signal " &
22+ "delivered to one of them crashes inside the handler".}
23+
1924 const libCosmicFfi* {.strdefine.} = currentSourcePath().parentDir /
2025 "libcosmic_ffi.so"
2126 ## Absolute at compile time, so the library is found wherever nimble put
@@ -16,6 +16,11 @@
16 16
17 import std/os17 import std/os
18 18
19+when not defined(noSignalHandler):
20+ {.warning: "compile with -d:noSignalHandler: libcosmic runs threads Nim " &
21+ "did not create, and Nim's signal handler allocates, so a signal " &
22+ "delivered to one of them crashes inside the handler".}
23+
19 const libCosmicFfi* {.strdefine.} = currentSourcePath().parentDir /24 const libCosmicFfi* {.strdefine.} = currentSourcePath().parentDir /
20 "libcosmic_ffi.so"25 "libcosmic_ffi.so"
21 ## Absolute at compile time, so the library is found wherever nimble put26 ## Absolute at compile time, so the library is found wherever nimble put