Repository navigation
Fantom's Debug tester sometimes dereferences a null runtime when many testers start at once: the inspector it starts by default has not posted the first task when loadScript drains the queue #59695
Description
Description
When I run Fantom's suites, some testers die of SIGSEGV before any test runs, with nothing on stdout or stderr. It happens more often the more testers run at once, so a full yarn fantom run on a machine with many cores meets it in a few suites.
The tester is a Debug build, and a Debug build turns the inspector on by default (ReactInstanceConfig.h L22-L28); the tester's main only ever sets enableInspector to true, for --inspectorPort (main.cpp L48-L56). With an inspector, ReactInstance gives the runtime scheduler an executor that buffers every task until the inspector's thread has registered the runtime and flushed it (ReactInstance.cpp L112-L150), and only then is the scheduler's event loop posted to the tester's StubQueue.
TesterAppDelegate::loadScript schedules the task that sets runtime_, drains the queue once, and loadScriptAndRunTests then reads runtime_ (TesterAppDelegate.cpp L168-L192). When the inspector's thread is late, which CPU contention makes likely, the queue is still empty when it is drained: runtime_ stays null and line 187 dereferences it.
In a 0.88.0 build of the tester I looked at a core of one of these crashes: runtime_ was null, the queue was empty, and the scheduler had isEventLoopScheduled_ = true with its tasks still queued. A StubQueue that logged the thread of each post showed the InspectorThread posting before the drain in the runs that passed, and no post from it before the drain in the run that crashed.
With enableInspector = false in the tester's config, so the inspector starts only for --inspectorPort, the same loop never crashes.
Steps to reproduce
-
git clone https://github.com/YevheniiKotyrlo/react-native-fantom-reproducer && cd react-native-fantom-reproducer -
./fantom/reproduce.sh concurrent-testers-null-runtime(needs Docker). It clonesreact/react-nativeatmain, builds Fantom's tester as CI does, runsView-itest.jsonce throughyarn fantomto bundle it, then starts 16 testers at once on that bundle, 200 times, with the argumentsyarn fantomgives a test:private/react-native-fantom/build/tester/fantom_tester --bundlePath <bundle> --featureFlags '{}' --minLogLevel error
Then it applies
fantom/tester-inspector-off.patch, which sets.enableInspector = falseinmain.cpp, rebuilds, and runs the same 200 rounds.
Expected: every tester exits 0.
Actual: on main at 97f6997, 74 of the 3,200 stock testers exited with status 139 and printed nothing; with the inspector off, all 3,200 exited 0.
React Native Version
0.88.0 (reproduced on main at 97f6997)
Affected Platforms
Build - Linux
Output of npx @react-native-community/cli info
System:
OS: Linux 6.18 Ubuntu 22.04.5 LTS 22.04.5 LTS (Jammy Jellyfish)
CPU: (24) x64 AMD Ryzen 9 9950X3D 16-Core Processor
Memory: 116.43 GB / 125.63 GB
Shell:
version: 5.1.16
path: /bin/bash
Binaries:
Node:
version: 22.14.0
path: /usr/local/bin/node
Yarn:
version: 1.22.22
path: /usr/local/bin/yarn
npm:
version: 10.9.2
path: /usr/local/bin/npm
Watchman: Not Found
SDKs:
Android SDK:
API Levels:
- "37"
Build Tools:
- 37.0.0
Android NDK: 28.2.13676358
IDEs:
Android Studio: Not Found
Languages:
Java:
version: 17.0.20.1
path: /usr/bin/javac
Ruby:
version: 3.0.2
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react: Not Found
react-native: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
Stacktrace or Logs
react-native 97f6997ee347f9e406787da9c97fde687cebdda1, committed 2026-10-30T21:22:43+00:00
clang version 23.1.3 (https://github.com/llvm/llvm-project 0d261d1ca552c95a8f007e061c787ac7132fbcbc)
bundle private/react-native-fantom/.out/js-builds/run-1793396836098/1793396849817-View-itest.js.bundle.js
== the stock tester
round 25, tester 10: exit status 139, 0 bytes on stdout and stderr
round 25, tester 13: exit status 139, 0 bytes on stdout and stderr
round 26, tester 7: exit status 139, 0 bytes on stdout and stderr
round 35, tester 16: exit status 139, 0 bytes on stdout and stderr
round 37, tester 16: exit status 139, 0 bytes on stdout and stderr
...
3200 testers, 74 exited non-zero
== the tester with enableInspector = false
3200 testers, 0 exited non-zero
MANDATORY Reproducer
https://github.com/YevheniiKotyrlo/react-native-fantom-reproducer
Screenshots and Videos
No response
Activity
YevheniiKotyrlo commentedon Oct 30, 2026
This is the part of the patch I carry for this that
mainstill needs (itsStubQueuelock is already there since #59015): the tester starts the inspector only for--inspectorPort, soloadScriptdrains a queue that holds the first task.