Skip to content

fix(scripting-node): stop node from clobbering Mono's SIGSEGV handler on POSIX - #4107

Open
valerisn wants to merge 1 commit into
citizenfx:masterfrom
valerisn:fix/mono-nre-linux-sigsegv
Open

fix(scripting-node): stop node from clobbering Mono's SIGSEGV handler on POSIX#4107
valerisn wants to merge 1 commit into
citizenfx:masterfrom
valerisn:fix/mono-nre-linux-sigsegv

Conversation

@valerisn

@valerisn valerisn commented Aug 4, 2026

Copy link
Copy Markdown

Goal of this PR

Fixes #4055.

On Linux, a null dereference inside a try/catch in a C# (mono v1) resource kills the entire FXServer process instead of throwing a catchable System.NullReferenceException. The same code catches fine on Windows.

Cause

Not the Breakpad crash handler. InitializeExceptionHandler (server/launcher/src/ServerMiniDump.cpp) runs long before mono, so mono's mono_sigsegv_signal_handler ends up installed on top of it and chains back correctly (mono_set_crash_chaining / mono_set_signal_chaining in MonoComponentHostShared.cpp).

The handler is overwritten by node. node::InitializeOncePerProcess is called with default flags in NodeParentEnvironment::Initialize, and on POSIX node installs a bare sigaction(SIGSEGV, ...) for the WebAssembly trap handler that does not chain to the previously installed handler. Components initialize in alphabetical order, so citizen-scripting-mono sets up mono's handler and citizen-scripting-node replaces it immediately after.

From that point on, every implicit null check in JIT''ed managed code lands in node''s TrapWebAssemblyOrContinue, V8 declines to handle it, and node re-raises SIGSEGV with stdio reset - the process dies with no managed output and the catch block never runs. Windows is unaffected because mono uses SEH there.

This is the same class of problem as 76da0fe (v8: disable in-process stack dumping to prevent Mono''s SIGSEGV handler from being overwritten).

How is this PR achieving the goal

Passes --disable-wasm-trap-handler to node on non-Windows targets. Node then skips the sigaction call entirely and V8 emits explicit bounds checks for WebAssembly memory instead, which is what it already does on any platform where the trap handler is unavailable.

ProcessInitializationFlags::kNoDefaultSignalHandling would also work, but it additionally drops node''s SIGPIPE ignore and its SIGINT/SIGTERM/SIGHUP handling, which is a far wider behaviour change than this issue calls for.

The option is a per-process CLI option available since node v22.2.0 (vendor is pinned at 22.22.0) and is parsed before the trap handler block in InitializeOncePerProcessInternal, so it takes effect.

This PR applies to the following area(s)

FXServer, C# / Mono, Node

Successfully tested on

Reasoned at source level; I do not have a Linux build environment set up to verify at runtime. The repro from the issue is the check - with this change nretest should print caught: System.NullReferenceException and leave the server running.

Checklist

  • Changes are limited to a single goal
  • Code compiles without new warnings (change is a single argument added to an existing list)
  • This PR does not introduce a breaking change

Trade-off

WebAssembly running inside server-side JS resources is bounds-checked in software rather than via guard pages on Linux. Marginal, and only affects resources actually using WASM.

… on POSIX

Node installs its own SIGSEGV handler for the WebAssembly trap handler during
InitializeOncePerProcess, replacing the one Mono uses to convert null
dereferences in managed code into NullReferenceExceptions. Since the node
component initializes after the Mono ones, a caught NRE would instead take the
whole server process down on Linux.
@github-actions github-actions Bot added the invalid Requires changes before it's considered valid and can be (re)triaged label Aug 4, 2026
@Sasino97

Sasino97 commented Aug 5, 2026

Copy link
Copy Markdown

As a FiveM C# user, I appreciate you 💖

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

invalid Requires changes before it's considered valid and can be (re)triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linux: NullReferenceException in C# (mono v1) kills the entire server process — same code catches fine on Windows

2 participants