Skip to content

Guard deferred Fabric surface start against concurrent unregister (#57404)#57404

Open
dmiliuts wants to merge 1 commit into
react:mainfrom
dmiliuts:export-D109477868
Open

Guard deferred Fabric surface start against concurrent unregister (#57404)#57404
dmiliuts wants to merge 1 commit into
react:mainfrom
dmiliuts:export-D109477868

Conversation

@dmiliuts

@dmiliuts dmiliuts commented Jul 1, 2026

Copy link
Copy Markdown

Summary:

-[RCTFabricSurface start] defers SurfaceHandler::start() across two async hops after its synchronous Registered check. If a concurrent RCTInstance teardown unregisters the surface in that window, the deferred start() dereferences a now-null link_.uiManager — debug aborts on the react_native_assert, release null-derefs. It is a TOCTOU: -[RCTInstance invalidate] tears down asynchronously on the JS thread with no completion signal, so an app-layer barrier cannot order against it — the start path itself must tolerate a concurrently-unregistered surface.

Fix: re-check getStatus() == Registered inside the deferred block before calling start(). Behavior-preserving on the success path; only the already-broken unregistered case changes from crash to a cancelled start.

Scope: iOS only. A companion cross-platform guard in SurfaceHandler::start() (return + LOG(ERROR) instead of the dev-fatal/release-compiled-out assert) would close the residual window between the re-check and start() atomically; left out to keep this iOS-only — happy to add if reviewers prefer. Flagging for code-owner review since this is core surface-start code.

Repro: an in-process React host teardown + rebuild that unregisters a surface while its deferred start is still queued.

Changelog: [iOS][Fixed] - Cancel a deferred Fabric surface start when the surface was unregistered by a concurrent instance teardown, instead of dereferencing a null UIManager

Differential Revision: D109477868

@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 Jul 1, 2026
@meta-codesync

meta-codesync Bot commented Jul 1, 2026

Copy link
Copy Markdown

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

@facebook-github-tools facebook-github-tools Bot added p: Facebook Partner: Facebook Partner labels Jul 1, 2026
@meta-codesync meta-codesync Bot changed the title Guard deferred Fabric surface start against concurrent unregister Guard deferred Fabric surface start against concurrent unregister (#57404) Jul 1, 2026
dmiliuts added a commit to dmiliuts/react-native that referenced this pull request Jul 1, 2026
…act#57404)

Summary:

`-[RCTFabricSurface start]` defers `SurfaceHandler::start()` across two async hops after its synchronous `Registered` check. If a concurrent `RCTInstance` teardown unregisters the surface in that window, the deferred `start()` dereferences a now-null `link_.uiManager` — debug aborts on the `react_native_assert`, release null-derefs. It is a TOCTOU: `-[RCTInstance invalidate]` tears down asynchronously on the JS thread with no completion signal, so an app-layer barrier cannot order against it — the start path itself must tolerate a concurrently-unregistered surface.

Fix: re-check `getStatus() == Registered` inside the deferred block before calling `start()`. Behavior-preserving on the success path; only the already-broken unregistered case changes from crash to a cancelled start.

Scope: iOS only. A companion cross-platform guard in `SurfaceHandler::start()` (return + `LOG(ERROR)` instead of the dev-fatal/release-compiled-out assert) would close the residual window between the re-check and `start()` atomically; left out to keep this iOS-only — happy to add if reviewers prefer. Flagging for code-owner review since this is core surface-start code.

Repro: an in-process React host teardown + rebuild that unregisters a surface while its deferred start is still queued.

Changelog: [iOS][Fixed] - Cancel a deferred Fabric surface start when the surface was unregistered by a concurrent instance teardown, instead of dereferencing a null UIManager

Differential Revision: D109477868
@dmiliuts dmiliuts force-pushed the export-D109477868 branch from 20207ad to 473e62d Compare July 1, 2026 20:02
…act#57404)

Summary:

`-[RCTFabricSurface start]` defers `SurfaceHandler::start()` across two async hops after its synchronous `Registered` check. If a concurrent `RCTInstance` teardown unregisters the surface in that window, the deferred `start()` dereferences a now-null `link_.uiManager` — debug aborts on the `react_native_assert`, release null-derefs. It is a TOCTOU: `-[RCTInstance invalidate]` tears down asynchronously on the JS thread with no completion signal, so an app-layer barrier cannot order against it — the start path itself must tolerate a concurrently-unregistered surface.

Fix: re-check `getStatus() == Registered` inside the deferred block before calling `start()`. Behavior-preserving on the success path; only the already-broken unregistered case changes from crash to a cancelled start.

Scope: iOS only. A companion cross-platform guard in `SurfaceHandler::start()` (return + `LOG(ERROR)` instead of the dev-fatal/release-compiled-out assert) would close the residual window between the re-check and `start()` atomically; left out to keep this iOS-only — happy to add if reviewers prefer. Flagging for code-owner review since this is core surface-start code.

Repro: an in-process React host teardown + rebuild that unregisters a surface while its deferred start is still queued.

Changelog: [iOS][Fixed] - Cancel a deferred Fabric surface start when the surface was unregistered by a concurrent instance teardown, instead of dereferencing a null UIManager

Differential Revision: D109477868
@dmiliuts dmiliuts force-pushed the export-D109477868 branch from 473e62d to f1488ec Compare July 1, 2026 20:04
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. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant