Skip to content

Node-API (JavaScriptCore): only erase the environment registry entry we own - #238

Open
matthargett wants to merge 2 commits into
BabylonJS:mainfrom
rebeckerspecialties:jsc-env-registry-guard
Open

matthargett wants to merge 2 commits into
BabylonJS:mainfrom
rebeckerspecialties:jsc-env-registry-guard

Conversation

@matthargett

Copy link
Copy Markdown

The JavaScriptCore backend keeps a static JSGlobalContextRef -> napi_env registry so host callbacks (CallAsConstructor, CallAsFunction, …) can recover their env from the context. napi_env__'s destructor erased the entry by context pointer, unconditionally.

Detach deliberately runs after JSGlobalContextRelease (finalizers still need the env), so between the release and the destructor JavaScriptCore can hand a new environment the very same context address; the new env registers it, and the old destructor then erases the new environment's entry. Its next callback resolves ToNapi() to nullptr and dereferences it — a SIGSEGV inside NativeInfo::Query (Linux shows it as an abort).

With one environment per process this is latent, which is why it never showed up; it reproduces immediately with environments created and torn down in quick succession (a worker-style create/terminate loop, which is how we found it). The fix erases the entry only if it still maps to this environment. No behavior change for the single-environment case.

Fork CI twin (full matrix): rebeckerspecialties#23.

…we own

The JavaScriptCore backend maps JSGlobalContextRef -> napi_env in a static registry
so host callbacks can recover their env from the context. The env destructor erased
the entry by context pointer unconditionally. Detach runs after JSGlobalContextRelease
(finalizers still need the env), so between the release and the destructor a *new*
environment can be handed the same context address and register it; the old
destructor then erased the new environment's entry, and its next callback resolved
ToNapi() to nullptr and dereferenced it (SIGSEGV inside NativeInfo::Query).

With a single environment this never happens, which is why it stayed latent; it
surfaced immediately once environments were created and torn down in quick
succession (a worker-style create/terminate loop). Erase the entry only if it still
maps to this environment.
Copilot AI lite review requested due to automatic review settings September 14, 2026 09:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Concurrent registry access remains unsynchronized and requires mutex protection.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Fixes JavaScriptCore environment registry cleanup so stale environments cannot erase newer registrations.

Changes:

  • Makes cleanup ownership-aware.
  • Preserves callback resolution during rapid environment recreation.
File summaries
File Description
Core/Node-API/Source/js_native_api_javascriptcore.h Adds identity-checked registry cleanup.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Core/Node-API/Source/js_native_api_javascriptcore.h
Environments live on their own runtime threads, so registration, lookup
and the conditional erase all touch one std::unordered_map concurrently.
@matthargett

Copy link
Copy Markdown
Author

Review addressed in 6f4e7e2 (registry mutex). Fork twin rebeckerspecialties#23 at that head: 24/24 green — https://github.com/rebeckerspecialties/JsRuntimeHost/actions/runs/34841396941

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants