feat(build): enforce -d:noSignalHandler at compile time

A nim-ffi library is loaded into a foreign host (Go/Rust/...) that must
own OS signal handling; if the Nim runtime installs its own handlers it
clobbers the host's (e.g. Go's SIGSEGV -> sigpanic recovery, stack
growth, goroutine preemption), turning recoverable faults into hard
process crashes. The flag can only be set on the consumer's final build
command, so a dependency cannot inject it -- but it CAN refuse to
compile without it. Add a compile-time guard so any consumer that omits
-d:noSignalHandler fails the build with an actionable message instead of
crashing at runtime (the cause of a real status-go regression).
Standalone Nim binaries (nim-ffi's own tests) build with
-d:ffiAllowSignalHandler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ivan FB 2026-06-09 23:47:30 +02:00
parent f6a3a338c0
commit d4c87c1f94
No known key found for this signature in database
GPG Key ID: DF0C67A04C543270
2 changed files with 16 additions and 3 deletions

View File

@ -1,6 +1,6 @@
# ffi.nimble
version = "0.1.5"
version = "0.1.6"
author = "Institute of Free Technology"
description = "FFI framework with custom header generation"
license = "MIT or Apache License 2.0"
@ -12,8 +12,8 @@ requires "chronos"
requires "chronicles"
requires "taskpools"
const nimFlagsOrc = "--mm:orc -d:chronicles_log_level=WARN"
const nimFlagsRefc = "--mm:refc -d:chronicles_log_level=WARN"
const nimFlagsOrc = "--mm:orc -d:chronicles_log_level=WARN -d:ffiAllowSignalHandler"
const nimFlagsRefc = "--mm:refc -d:chronicles_log_level=WARN -d:ffiAllowSignalHandler"
task buildffi, "Compile the library":
exec "nim c " & nimFlagsOrc & " --app:lib --noMain ffi.nim"

View File

@ -2,6 +2,19 @@
{.pragma: callback, cdecl, raises: [], gcsafe.}
{.passc: "-fPIC".}
# Embedded in a foreign host (Go/Rust/...) the host must own OS signal handling;
# Nim installing its own handlers clobbers it (e.g. Go's SIGSEGV -> sigpanic).
# Enforce -d:noSignalHandler; standalone Nim binaries opt out via -d:ffiAllowSignalHandler.
when not defined(noSignalHandler) and not defined(ffiAllowSignalHandler):
{.
error:
"nim-ffi: missing required compile flag. If this library is embedded in a " &
"host process (Go/Rust/...), build with -d:noSignalHandler so the host keeps " &
"ownership of OS signal handlers (it needs SIGSEGV for crash recovery, stack " &
"growth and preemption). If instead this is a standalone Nim program that owns " &
"its own process, build with -d:ffiAllowSignalHandler."
.}
import std/[atomics, locks, json, tables, sequtils]
import chronicles, chronos, chronos/threadsync, taskpools/channels_spsc_single, results
import ./ffi_types, ./ffi_thread_request, ./internal/ffi_macro, ./logging