From 0104d8c11e38a9ea069d6eb879546899ce704366 Mon Sep 17 00:00:00 2001 From: Bartlomiej Bloniarz Date: Thu, 16 Apr 2026 04:45:57 -0700 Subject: [PATCH] Avoid moving RawProps during animation backend commit when retries are possible Summary: The `cloneProps` function in `AnimationBackend.cpp` was using `std::move(*animatedProps.rawProps)` inside a `shadowTree.commit()` transaction lambda. Since commits can be retried (when `currentRevision_.number != oldRevision.number`), the moved-from `RawProps` would be in an unspecified state on the second attempt, leading to incorrect or undefined behavior. When `enableFabricCommitBranching` is enabled, commit retries are not a concern, so moving is safe. When disabled, we now copy via `RawProps(*animatedProps.rawProps)` instead. This is the only dangerous move in the animation backend commit path. The `AnimationBackendCommitHook` already copies correctly (`RawProps(*snapshot->rawProps)`), and `AnimatedPropsRegistry::getMap()` is safe because moved pending data persists in the `map` member across retries. Changelog: [General][Fixed] - Fix potential data corruption in animation backend when ShadowTree commits are retried by copying RawProps instead of moving them Differential Revision: D101161363 --- .../animationbackend/AnimationBackend.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp index 2d73065a10cd..789bb1fc4f7f 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp @@ -24,10 +24,17 @@ static inline Props::Shared cloneProps( shadowNode.getSurfaceId(), *shadowNode.getContextContainer()}; Props::Shared newProps; if (animatedProps.rawProps) { - newProps = shadowNode.getComponentDescriptor().cloneProps( - propsParserContext, - shadowNode.getProps(), - std::move(*animatedProps.rawProps)); + if (ReactNativeFeatureFlags::enableFabricCommitBranching()) { + newProps = shadowNode.getComponentDescriptor().cloneProps( + propsParserContext, + shadowNode.getProps(), + std::move(*animatedProps.rawProps)); + } else { + newProps = shadowNode.getComponentDescriptor().cloneProps( + propsParserContext, + shadowNode.getProps(), + RawProps(*animatedProps.rawProps)); + } } else { newProps = shadowNode.getComponentDescriptor().cloneProps( propsParserContext, shadowNode.getProps(), {});