Skip to content

Add unit test for RuntimeExecutor post-shutdown safety#56995

Closed
javache wants to merge 2 commits into
facebook:mainfrom
javache:export-D106783789
Closed

Add unit test for RuntimeExecutor post-shutdown safety#56995
javache wants to merge 2 commits into
facebook:mainfrom
javache:export-D106783789

Conversation

@javache
Copy link
Copy Markdown
Member

@javache javache commented May 29, 2026

Summary:
The RuntimeExecutor returned by ReactInstance::getBufferedRuntimeExecutor() is designed to be safe to hold past the lifetime of the ReactInstance itself — callers may schedule work on it after shutdown without crashing, and any pending callbacks must be dropped rather than surfaced on the JS queue.

This contract relies on weak_ptr captures inside the executor closure and inside the base closure in the ReactInstance constructor. Today nothing tests it directly — coverage is incidental through ReactInstanceTest happy-path cases — so a future refactor that swaps a weak_ptr capture for a shared_ptr (keeping the runtime alive) or a raw pointer (introducing UAF) could silently regress.

Adds three focused regression tests covering:

  • Calling the held executor after ReactInstance destruction drops the callback (no queuing, no execution).
  • Repeated post-shutdown invocations remain memory-safe.
  • Work buffered in BufferedRuntimeExecutor before shutdown is dropped, never surfaced on the JS queue.

The new test file lands under the existing tests target's glob(["tests/**/*.cpp"]), so no BUCK changes are needed.

Note: this test deliberately targets the buffered API only. getUnbufferedRuntimeExecutor() captures runtimeScheduler_.get() as a raw pointer and is not safe to hold past shutdown by design — a separate concern, out of scope here.

Changelog:
[Internal]

Differential Revision: D106783789

javache added 2 commits May 29, 2026 03:59
Summary:

Add `ReactContext.getRuntimeExecutor()` so callers can obtain the `RuntimeExecutor` without reaching into `CatalystInstance`. The bridge subclass forwards to `CatalystInstance.getRuntimeExecutor()`; the bridgeless subclass forwards to `ReactHost.runtimeExecutor`; `ThemedReactContext` proxies to its wrapped `ReactApplicationContext`. Previously, callers that needed the runtime executor had to reach through `catalystInstance.getRuntimeExecutor()`, which is bridge-only and required a `NoGetCatalystInstance` lint suppression. The new accessor works uniformly in both bridged and bridgeless modes.

Changelog:
[Android][Added] - Add `ReactContext.getRuntimeExecutor()`

Differential Revision: D106647233
Summary:
The `RuntimeExecutor` returned by `ReactInstance::getBufferedRuntimeExecutor()` is designed to be safe to hold past the lifetime of the `ReactInstance` itself — callers may schedule work on it after shutdown without crashing, and any pending callbacks must be dropped rather than surfaced on the JS queue.

This contract relies on `weak_ptr` captures inside the executor closure and inside the base closure in the `ReactInstance` constructor. Today nothing tests it directly — coverage is incidental through `ReactInstanceTest` happy-path cases — so a future refactor that swaps a `weak_ptr` capture for a `shared_ptr` (keeping the runtime alive) or a raw pointer (introducing UAF) could silently regress.

Adds three focused regression tests covering:

- Calling the held executor after `ReactInstance` destruction drops the callback (no queuing, no execution).
- Repeated post-shutdown invocations remain memory-safe.
- Work buffered in `BufferedRuntimeExecutor` before shutdown is dropped, never surfaced on the JS queue.

The new test file lands under the existing `tests` target's `glob(["tests/**/*.cpp"])`, so no BUCK changes are needed.

Note: this test deliberately targets the buffered API only. `getUnbufferedRuntimeExecutor()` captures `runtimeScheduler_.get()` as a raw pointer and is not safe to hold past shutdown by design — a separate concern, out of scope here.

Changelog:
[Internal]

Differential Revision: D106783789
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 29, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented May 29, 2026

@javache has exported this pull request. If you are a Meta employee, you can view the originating Diff in D106783789.

@react-native-bot
Copy link
Copy Markdown
Collaborator

This pull request was successfully merged by @javache in b043c27

When will my fix make it into a release? | How to file a pick request?

@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented May 29, 2026

This pull request has been merged in b043c27.

@facebook-github-tools facebook-github-tools Bot added the Merged This PR has been merged. label May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants