Skip to content

[JS/React Native] iOS crash on bridge teardown: OnnxruntimeModule dealloc segfaults clearing static jsi::Env #29197

Description

@ps-george

Describe the issue

onnxruntime-react-native (1.24.3, iOS) crashes with EXC_BAD_ACCESS on bridge teardown / fast refresh / app close. The faulting frame is -[OnnxruntimeModule dealloc]std::shared_ptr<onnxruntimejsi::Env>::resetfacebook::jsi::WeakObject::~WeakObject() → null deref.

Root cause

OnnxruntimeModule.mm clears the static env shared_ptr inside -dealloc:

static std::shared_ptr<onnxruntimejsi::Env> env;
...
- (void)dealloc {
  env.reset();
}

env holds JSI WeakObjects bound to the bridge's JSI runtime. React Native's teardown order is roughly:

  1. Bridge marks modules invalid (invalidate)
  2. JSI runtime is destroyed
  3. Module Obj-C instances are released (dealloc)

By step 3 the runtime is already gone, so ~WeakObject() accesses freed memory and segfaults. This is reliably reproducible on cold-launch followed by app close, on fast refresh, and on bridge reload.

Crash signature (iOS sim, RN 0.81, Hermes)

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000

Thread (com.facebook.react.runtime.JavaScript):
  facebook::jsi::Pointer::~Pointer()
  facebook::jsi::WeakObject::~WeakObject()
  std::shared_ptr<facebook::jsi::WeakObject>::~shared_ptr()
  onnxruntimejsi::Env::~Env()
  std::shared_ptr<onnxruntimejsi::Env>::reset()
  -[OnnxruntimeModule dealloc]
  AutoreleasePoolPage::releaseUntil(...)
  objc_autoreleasePoolPop
  facebook::react::RCTMessageThread::runAsync(...)

Fix

Move the env.reset() out of dealloc into -invalidate (RN's documented hook that fires BEFORE the JSI runtime is torn down). Adopt RCTInvalidating:

@interface OnnxruntimeModule () <RCTInvalidating>
@end

@implementation OnnxruntimeModule
...
- (void)invalidate {
  env.reset();   // runtime is still alive here; WeakObjects can die safely
}

- (void)dealloc {
  // no-op: env already cleared in -invalidate
}
@end

I'm running this locally as a patch-package patch and the crash is gone. Happy to send a PR if useful — just wanted to file the issue first in case there's context on why the static env is owned by the module instance rather than a runtime-scoped install/uninstall pair.

Reproduction steps

  1. Install onnxruntime-react-native@1.24.3 in a vanilla Expo 54 / RN 0.81 app
  2. Call InferenceSession.create(...) once at startup so the JSI install runs
  3. Close the app or trigger a fast refresh
  4. EXC_BAD_ACCESS appears in ~/Library/Logs/DiagnosticReports/ immediately

Urgency

Medium — the crash is on teardown so users on RC builds usually don't see it, but it shows up in TestFlight crash logs and breaks dev fast-refresh on any project that pulls in the package.

Platform

iOS (sim + device, arm64). Android is unaffected — the JNI module clears its refs differently.

Version

onnxruntime-react-native 1.24.3, React Native 0.81, iOS 18.x simulator + device, Hermes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api:Javascriptissues related to the Javascript APIplatform:mobileissues related to ONNX Runtime mobile; typically submitted using templateplatform:webissues related to ONNX Runtime web; typically submitted using template

    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