Skip to content

PR #264 (static_h merge) reverted PR #259 "Fix weak reference creation" — weak-ref crash has regressed and is still missing on main #343

Description

@ericfle

Summary

PR #259 ("Fix weak reference creation", merged 2025-11-07) fixed intermittent AVs during Node-API weak-reference creation for HostObject/proxy-flagged objects. The subsequent upstream merge PR #264 ("Merge static_h branch from upstream Hermes repo", merged 2026-02-24) silently removed all of #259's changes from API/hermes_node_api/hermes_node_api.cpp, and they are still absent from main today. We are hitting the regressed crash in production.

Is that revert intentional because the issue was supposed to be fixed on the new code?

Evidence the fix was reverted

API/hermes_node_api/hermes_node_api.cpp, presence of #259's identifiers (needsFinalizerTracking, initializeStorage, and the isHostObject() || isProxyObject() rejection in getExternalPropertyValue):

Commit Date #259 code present?
d7ca19b3#259 merge 2025-11-07 yes (introduced)
bc3d0ed7#260 FB sync 2025-11-19 yes
4df97b14#264 static_h merge 2026-02-24 NO — all three removed
4d4c2836#280 sync 2026-03-10 no
94aa5e1d#311 (our shipped build) 2026-04-21 no
main (checked 2026-07-06) no

At 94aa5e1d, getExternalPropertyValue (lines 3660-3685) is back to the pre-#259 shape: getPredefinedProperty(...) then defineOwnProperty(...) with no HostObject/JSProxy rejection, and NodeApiReference has no needsFinalizerTracking()/initializeStorage().

The crash we observe after upgrading to RNW 0.81.27 (regressed build 0.0.0-2604.21001-94aa5e1d, win32-x86-release)

  • EXCEPTION_ACCESS_VIOLATION_READ @ 0x00000020 on the RN JS thread, intermittent, correlates with memory pressure (32-bit process near VA exhaustion; Hermes heap ~44 MB, 97.6% full, ~669 collections).
  • Repro workload: heavy UIManager.createNode churn; each node creation wraps the instance handle in a jsi::WeakObject:
UIManager.createNode (UIManagerBinding.cpp:216)
  → InstanceHandle ctor — jsi::WeakObject(runtime, instanceHandle)   (InstanceHandle.cpp:17)
  → NodeApiJsiRuntime::createWeakObject (:1830)
  → NodeApiRefCountedPointerValue::createNodeApiRef (:2260)
  → napi_create_reference → hermes.dll → AV

It looks like similar entry path as the stack in #259's description.

If it can be helpful:

Crash site (static disassembly of the shipped DLL)

Faulting instruction hermes.dll +0x22a59b, inside the function at +0x22a4b0, which is hermes::vm::detail::findTrap (JSProxy.cpp) with detail::slots() inlined:

// lib/VM/JSProxy.cpp:24 at 94aa5e1d
ProxySlots &slots(JSObject *self) {
  if (auto *proxy = dyn_vmcast<JSProxy>(self))        // CellKind 0x41 → slots_ @ +0x14
    return proxy->slots_;
  auto *cproxy = dyn_vmcast<JSCallableProxy>(self);   // CellKind 0x48 → slots_ @ +0x20
  assert(cproxy && "JSProxy methods must be passed JSProxy or JSCallableProxy");
  return cproxy->slots_;  // release: assert gone → &(((JSCallableProxy*)0)->slots_) == 0x20
}

Compiled x86 (verified in the shipped DLL):

+0x22a569: movzx edi, byte ptr [edx+3]     ; CellKind
+0x22a56d: shl   edi, 0x18
+0x22a570: cmp   edi, 0x41000000           ; JSProxy?
+0x22a576: mov   ebx, 0
+0x22a57b: cmove ebx, edx
+0x22a57e: cmp   edi, 0x48000000           ; JSCallableProxy?
+0x22a584: cmove esi, edx                  ; esi was zeroed
+0x22a58c: add   esi, 0x20                 ; nullptr->slots_ == 0x20 if neither kind
+0x22a591: lea   edx, [ebx+0x14]
+0x22a598: cmovne esi, edx
+0x22a59b: mov   edx, [esi]                ; <<< AV: reads 0x20

Fault registers match exactly: esi=0x20, edx=0x14, edi=0xffff0000.

So a JSProxy trap lookup is reached for an object that is neither JSProxy nor JSCallableProxy — the class of misroute #259's isProxyObject()/isHostObject() rejection in getExternalPropertyValue guarded against, during weak-reference finalizer-tracking setup.

Happy to provide the full symbolicated trace and disassembly notes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions