Skip to content

Commit c70f941

Browse files
coadoalanleedev
authored andcommitted
Fix unsafe rawPointer access in cloneMultiple (#55613)
Summary: Pull Request resolved: #55613 The cloneMultiple method was written in a way to accept a list of families that are presumed to be owned by the api caller. This designe was mostly aimed at reanimated, that holds refernces to ShadowNodes (that own these families). In the case of AnimationBackend this didn't work properly, as when the view is unmounted we would lose the ShadowNodeFamily shared_ptr that we hold and it could get deallocated. Since now we can get an owning reference to ShadowNodeFamily from ShadowNode::getFamilyShared, we don't have to keep this old unsafe api. Instead we require the caller to have an owning reference with the api itself. This `cloneMultiple` method isn't really adopted in the community, so the breaking change shouldn't be a big problem. Changelog: [General][Breaking] - fix unsafe rawPointer access in cloneMultiple. Reviewed By: zeyap, javache Differential Revision: D93596770 fbshipit-source-id: c4d99b51875968ebce50358c19502cba02c50685
1 parent 2394ead commit c70f941

File tree

7 files changed

+32
-27
lines changed

7 files changed

+32
-27
lines changed

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ void AnimatedPropsRegistry::update(
5555
}
5656
}
5757

58-
std::pair<std::unordered_set<const ShadowNodeFamily*>&, SnapshotMap&>
58+
std::pair<
59+
std::unordered_set<std::shared_ptr<const ShadowNodeFamily>>&,
60+
SnapshotMap&>
5961
AnimatedPropsRegistry::getMap(SurfaceId surfaceId) {
6062
auto lock = std::lock_guard(mutex_);
6163
auto& [pendingMap, map, pendingFamilies, families] =

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ struct PropsSnapshot {
2424

2525
struct SurfaceContext {
2626
std::unordered_map<Tag, std::unique_ptr<PropsSnapshot>> pendingMap, map;
27-
std::unordered_set<const ShadowNodeFamily *> pendingFamilies, families;
27+
std::unordered_set<std::shared_ptr<const ShadowNodeFamily>> pendingFamilies, families;
2828
};
2929

3030
struct SurfaceUpdates {
31-
std::unordered_set<const ShadowNodeFamily *> families;
31+
std::unordered_set<std::shared_ptr<const ShadowNodeFamily>> families;
3232
std::unordered_map<Tag, AnimatedProps> propsMap;
3333
bool hasLayoutUpdates{false};
3434
};
@@ -39,7 +39,7 @@ class AnimatedPropsRegistry {
3939
public:
4040
void update(const std::unordered_map<SurfaceId, SurfaceUpdates> &surfaceUpdates);
4141
void clear(SurfaceId surfaceId);
42-
std::pair<std::unordered_set<const ShadowNodeFamily *> &, SnapshotMap &> getMap(SurfaceId surfaceId);
42+
std::pair<std::unordered_set<std::shared_ptr<const ShadowNodeFamily>> &, SnapshotMap &> getMap(SurfaceId surfaceId);
4343

4444
private:
4545
std::unordered_map<SurfaceId, SurfaceContext> surfaceContexts_;

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void AnimationBackend::onAnimationFrame(AnimationTimestamp timestamp) {
7171
auto& [families, updates, hasLayoutUpdates] =
7272
surfaceUpdates[family->getSurfaceId()];
7373
hasLayoutUpdates |= mutation.hasLayoutUpdates;
74-
families.insert(family.get());
74+
families.insert(family);
7575
updates[mutation.tag] = std::move(mutation.props);
7676
}
7777
}
@@ -146,7 +146,8 @@ void AnimationBackend::commitUpdates(
146146
const ShadowNode& shadowNode,
147147
const ShadowNodeFragment& fragment) {
148148
auto newProps = ShadowNodeFragment::propsPlaceholder();
149-
if (surfaceFamilies.contains(&shadowNode.getFamily())) {
149+
if (surfaceFamilies.contains(
150+
shadowNode.getFamilyShared())) {
150151
auto& animatedProps = updates.at(shadowNode.getTag());
151152
newProps = cloneProps(animatedProps, shadowNode);
152153
}

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ RootShadowNode::Unshared AnimationBackendCommitHook::shadowTreeWillCommit(
4343
const ShadowNodeFragment& fragment) {
4444
auto newProps = ShadowNodeFragment::propsPlaceholder();
4545
std::shared_ptr<BaseViewProps> viewProps = nullptr;
46-
if (surfaceFamilies.contains(&shadowNode.getFamily()) &&
47-
updates.contains(shadowNode.getTag())) {
48-
auto& snapshot = updates.at(shadowNode.getTag());
46+
if (auto updatesIter = updates.find(shadowNode.getTag());
47+
updatesIter != updates.end() &&
48+
surfaceFamilies.contains(shadowNode.getFamilyShared())) {
49+
auto& snapshot = updatesIter->second;
4950
if (!snapshot->propNames.empty() || snapshot->rawProps) {
5051
PropsParserContext propsParserContext{
5152
shadowNode.getSurfaceId(),

packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -413,17 +413,16 @@ namespace {
413413

414414
std::shared_ptr<ShadowNode> cloneMultipleRecursive(
415415
const ShadowNode& shadowNode,
416-
const std::unordered_map<const ShadowNodeFamily*, int>& childrenCount,
416+
const std::unordered_map<Tag, int>& childrenCount,
417417
const std::function<std::shared_ptr<
418418
ShadowNode>(const ShadowNode&, const ShadowNodeFragment&)>& callback) {
419-
const auto* family = &shadowNode.getFamily();
420419
auto& children = shadowNode.getChildren();
421420
std::shared_ptr<std::vector<std::shared_ptr<const ShadowNode>>> newChildren;
422-
auto count = childrenCount.at(family);
421+
auto count = childrenCount.at(shadowNode.getTag());
423422

424423
for (size_t i = 0; count > 0 && i < children.size(); i++) {
425-
const auto childFamily = &children[i]->getFamily();
426-
if (childrenCount.contains(childFamily)) {
424+
const auto childTag = children[i]->getTag();
425+
if (childrenCount.contains(childTag)) {
427426
count--;
428427
if (!newChildren) {
429428
newChildren =
@@ -441,37 +440,39 @@ std::shared_ptr<ShadowNode> cloneMultipleRecursive(
441440
} // namespace
442441

443442
std::shared_ptr<ShadowNode> ShadowNode::cloneMultiple(
444-
const std::unordered_set<const ShadowNodeFamily*>& familiesToUpdate,
443+
const std::unordered_set<std::shared_ptr<const ShadowNodeFamily>>&
444+
familiesToUpdate,
445445
const std::function<std::shared_ptr<ShadowNode>(
446446
const ShadowNode& oldShadowNode,
447447
const ShadowNodeFragment& fragment)>& callback) const {
448-
std::unordered_map<const ShadowNodeFamily*, int> childrenCount;
448+
std::unordered_map<Tag, int> childrenCount;
449449

450450
for (const auto& family : familiesToUpdate) {
451-
if (childrenCount.contains(family)) {
451+
if (childrenCount.contains(family->getTag())) {
452452
continue;
453453
}
454454

455-
childrenCount[family] = 0;
455+
childrenCount[family->getTag()] = 0;
456456

457457
auto ancestor = family->parent_.lock();
458458
while ((ancestor != nullptr) && ancestor != family_) {
459-
auto ancestorIt = childrenCount.find(ancestor.get());
459+
auto ancestorTag = ancestor->getTag();
460+
auto ancestorIt = childrenCount.find(ancestorTag);
460461
if (ancestorIt != childrenCount.end()) {
461462
ancestorIt->second++;
462463
break;
463464
}
464-
childrenCount[ancestor.get()] = 1;
465+
childrenCount[ancestorTag] = 1;
465466

466467
ancestor = ancestor->parent_.lock();
467468
}
468469

469470
if (ancestor == family_) {
470-
childrenCount[ancestor.get()]++;
471+
childrenCount[ancestor->getTag()]++;
471472
}
472473
}
473474

474-
if (!childrenCount.contains(&this->getFamily())) {
475+
if (!childrenCount.contains(getTag())) {
475476
return nullptr;
476477
}
477478

packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class ShadowNode : public Sealable, public DebugStringConvertible, public jsi::N
109109
* Returns `nullptr` if the operation cannot be performed successfully.
110110
*/
111111
std::shared_ptr<ShadowNode> cloneMultiple(
112-
const std::unordered_set<const ShadowNodeFamily *> &familiesToUpdate,
112+
const std::unordered_set<std::shared_ptr<const ShadowNodeFamily>> &familiesToUpdate,
113113
const std::function<
114114
std::shared_ptr<ShadowNode>(const ShadowNode &oldShadowNode, const ShadowNodeFragment &fragment)> &callback)
115115
const;

packages/react-native/ReactCommon/react/renderer/core/tests/ShadowNodeTest.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ TEST_F(ShadowNodeTest, handleRuntimeReferenceTransferOnClone) {
316316
TEST_F(ShadowNodeTest, cloneMultiple) {
317317
auto newProps = std::make_shared<const TestProps>();
318318
auto newRoot = nodeA_->cloneMultiple(
319-
{&nodeA_->getFamily(), &nodeAB_->getFamily()},
319+
{nodeA_->getFamilyShared(), nodeAB_->getFamilyShared()},
320320
[&](const ShadowNode& oldShadowNode, const ShadowNodeFragment& fragment) {
321321
return oldShadowNode.clone({
322322
.props = newProps,
@@ -346,7 +346,7 @@ TEST_F(ShadowNodeTest, cloneMultiple) {
346346
TEST_F(ShadowNodeTest, cloneMultipleWithSingleFamily) {
347347
auto newProps = std::make_shared<const TestProps>();
348348
auto newRoot = nodeA_->cloneMultiple(
349-
{&nodeAB_->getFamily()},
349+
{nodeAB_->getFamilyShared()},
350350
[&](const ShadowNode& oldShadowNode, const ShadowNodeFragment& fragment) {
351351
return oldShadowNode.clone({
352352
.props = newProps,
@@ -379,7 +379,7 @@ TEST_F(ShadowNodeTest, cloneMultipleReturnsNullptrWhenFamilyHasNoPathToRoot) {
379379
auto newProps = std::make_shared<const TestProps>();
380380
// nodeZ_ is not part of nodeA_'s tree
381381
auto result = nodeA_->cloneMultiple(
382-
{&nodeZ_->getFamily()},
382+
{nodeZ_->getFamilyShared()},
383383
[&](const ShadowNode& oldShadowNode, const ShadowNodeFragment& fragment) {
384384
return oldShadowNode.clone({
385385
.props = newProps,
@@ -396,7 +396,7 @@ TEST_F(ShadowNodeTest, cloneMultipleWithMixOfValidAndInvalidFamilies) {
396396
auto newProps = std::make_shared<const TestProps>();
397397
// nodeAB_ is in the tree, nodeZ_ is not
398398
auto result = nodeA_->cloneMultiple(
399-
{&nodeAB_->getFamily(), &nodeZ_->getFamily()},
399+
{nodeAB_->getFamilyShared(), nodeZ_->getFamilyShared()},
400400
[&](const ShadowNode& oldShadowNode, const ShadowNodeFragment& fragment) {
401401
return oldShadowNode.clone({
402402
.props = newProps,

0 commit comments

Comments
 (0)