Skip to content

Decide NativeAnimated backend per-instance instead of live flag (#57205)#57205

Closed
zeyap wants to merge 1 commit into
react:mainfrom
zeyap:export-D108428720
Closed

Decide NativeAnimated backend per-instance instead of live flag (#57205)#57205
zeyap wants to merge 1 commit into
react:mainfrom
zeyap:export-D108428720

Conversation

@zeyap

@zeyap zeyap commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary:

Changelog:

[Internal][Fixed] - Fix EXC_BAD_ACCESS / KERN_INVALID_ADDRESS in C++ Animated when useSharedAnimatedBackend() flips across a reused runtime

C++ Animated chose between the legacy and shared-AnimationBackend code paths by reading ReactNativeFeatureFlags::useSharedAnimatedBackend() live, in many places. That flag is a process-global singleton (ReactNativeFeatureFlags::accessor_). On some app the global is reset and re-applied on every user switch (FBReactModule setUpReactNativeFeatureFlags -> dangerouslyReset()/override()), and the previous user's runtime is kept alive and reused. The shared AnimationBackend is attached only once, when an instance's Scheduler is constructed, gated on the flag at that moment. On a multi-account device the global flag could therefore read true on a reused instance whose backend was never attached, so getOrCreate took the shared path and dereferenced a null backend. It also let JS and C++ disagree, since JS caches the flag per runtime while C++ followed the mutated global.

Fix: make the per-instance decision once and use it everywhere instead of the live flag.

  • NativeAnimatedNodesManagerProvider::getOrCreate selects the path by whether the shared AnimationBackend actually exists for this instance (unstable_getAnimationBackend().lock() != nullptr).
  • NativeAnimatedNodesManager stores a const bool useSharedAnimatedBackend_, latched in its constructor (true for the shared-backend ctor, false for the legacy ctor), and exposes it via useSharedAnimatedBackend(). All internal reads now use the member.
  • PropsAnimatedNode reads the decision through manager_->useSharedAnimatedBackend().

The attach side (Scheduler) is intentionally unchanged: it remains the single construction-time read that latches the per-instance decision the rest of the code now follows. This keeps JS and C++ consistent across global flag flips and removes the null dereference.

Reviewed By: sbuggay

Differential Revision: D108428720

@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 Jun 15, 2026
@meta-codesync

meta-codesync Bot commented Jun 15, 2026

Copy link
Copy Markdown

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

…t#57205)

Summary:

## Changelog:

[Internal][Fixed] - Fix EXC_BAD_ACCESS / KERN_INVALID_ADDRESS in C++ Animated when `useSharedAnimatedBackend()` flips across a reused runtime

C++ Animated chose between the legacy and shared-`AnimationBackend` code paths by reading `ReactNativeFeatureFlags::useSharedAnimatedBackend()` live, in many places. That flag is a process-global singleton (`ReactNativeFeatureFlags::accessor_`). On some app the global is reset and re-applied on every user switch (`FBReactModule setUpReactNativeFeatureFlags` -> `dangerouslyReset()`/`override()`), and the previous user's runtime is kept alive and reused. The shared `AnimationBackend` is attached only once, when an instance's `Scheduler` is constructed, gated on the flag at that moment. On a multi-account device the global flag could therefore read true on a reused instance whose backend was never attached, so `getOrCreate` took the shared path and dereferenced a null backend. It also let JS and C++ disagree, since JS caches the flag per runtime while C++ followed the mutated global.

Fix: make the per-instance decision once and use it everywhere instead of the live flag.

- `NativeAnimatedNodesManagerProvider::getOrCreate` selects the path by whether the shared `AnimationBackend` actually exists for this instance (`unstable_getAnimationBackend().lock() != nullptr`).
- `NativeAnimatedNodesManager` stores a `const bool useSharedAnimatedBackend_`, latched in its constructor (true for the shared-backend ctor, false for the legacy ctor), and exposes it via `useSharedAnimatedBackend()`. All internal reads now use the member.
- `PropsAnimatedNode` reads the decision through `manager_->useSharedAnimatedBackend()`.

The attach side (`Scheduler`) is intentionally unchanged: it remains the single construction-time read that latches the per-instance decision the rest of the code now follows. This keeps JS and C++ consistent across global flag flips and removes the null dereference.

Reviewed By: sbuggay

Differential Revision: D108428720
@meta-codesync meta-codesync Bot changed the title Decide NativeAnimated backend per-instance instead of live flag Decide NativeAnimated backend per-instance instead of live flag (#57205) Jun 15, 2026
@zeyap zeyap force-pushed the export-D108428720 branch from cdacb60 to 159d395 Compare June 15, 2026 14:41
@meta-codesync meta-codesync Bot closed this in dd5c383 Jun 15, 2026
@meta-codesync meta-codesync Bot added the Merged This PR has been merged. label Jun 15, 2026
@meta-codesync

meta-codesync Bot commented Jun 15, 2026

Copy link
Copy Markdown

This pull request has been merged in dd5c383.

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. 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.

1 participant