initializeLibrary ran NimMain only on the thread that won
`initialized.exchange(true)`; concurrent first-time callers fell straight
through and used a half-initialized Nim runtime — a heap-corrupting race
when multiple foreign (e.g. Go) threads create the first context at once.
Add an `initDone` flag the winner sets after NimMain; the others spin
until it is set before proceeding.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
myLib lives in non-GC `createShared` memory, so under --mm:refc a
GC-managed lib object stored there is invisible to the cycle collector
and gets reclaimed mid-operation under sustained request load — a
use-after-free that crashes deep in the lib (e.g. a held chronos
AsyncLock). Take a GC_ref once a handler installs myLib (tracked by
FFIContext.myLibRefd) and GC_unref in freeLib so a later recycle/create
can re-pin. Guarded to refc + ref types; orc tracks it precisely.
Also wrap freeLib's `=destroy` in try/except: it is conservatively typed
as raising, and recycleContext (its async caller) is `raises: []`, so the
library would not compile under orc/arc without this.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ffiNewReq derived the request id with `let typeStr = $T`, allocating a
Nim GC string on the *calling* thread for every request. Embedded in a
foreign host (e.g. Go) the callers are transient, concurrent OS threads;
running Nim's GC there corrupts the heap under load. The type name is
known at compile time, so emit it as a `cstring` literal (the same value
already used as the registry key) — no runtime allocation. Applies to
both the {.ffi.} and {.ffiCtor.} request builders.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
* protect against mem leak in case of failures sending requests to ffi thread
* better cleanup if failures in createFFIContext
* avoid dangling cstring in handleRes under ARC/ORC
* better resource cleanup in destroyFFIContext
* invoke onNotResponding if failure in destroyFFIContext
* correct seq copy in alloc
* make sure the lock is init before cleanUpResources
* better possible exception handling in processReq
* guard allocSharedSeq if given seq is empty
* enhance error handling in ffi_context
* add new tests and some corrections