Use weak ptr for runtime shadow node reference (#45463)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/45463

Changelog: [Internal]

State updates will clone shadow nodes for an shadow tree revision that is outdated.

This can lead to accessing deallocated shadow node references because the JS renderer committed a newer revision and deallocated the one used by the pending state update.

By using a weak pointer to hold a reference to the runtime shadow node reference, we can only update references for wrappers that are still valid.

Reviewed By: javache

Differential Revision: D59804999

fbshipit-source-id: 89c9967d139d3cac7d7252994beae419bc591e79
This commit is contained in:
Nick Lefever
2024-07-16 09:23:42 -07:00
committed by Facebook GitHub Bot
parent 2098806c22
commit c0b288ca3f
4 changed files with 11 additions and 10 deletions
@@ -310,7 +310,8 @@ bool ShadowNode::progressStateIfNecessary() {
}
void ShadowNode::setRuntimeShadowNodeReference(
ShadowNodeWrapper* runtimeShadowNodeReference) const {
const std::shared_ptr<ShadowNodeWrapper>& runtimeShadowNodeReference)
const {
runtimeShadowNodeReference_ = runtimeShadowNodeReference;
}
@@ -319,8 +320,8 @@ void ShadowNode::transferRuntimeShadowNodeReference(
destinationShadowNode->runtimeShadowNodeReference_ =
runtimeShadowNodeReference_;
if (runtimeShadowNodeReference_ != nullptr) {
runtimeShadowNodeReference_->shadowNode = destinationShadowNode;
if (auto reference = runtimeShadowNodeReference_.lock()) {
reference->shadowNode = destinationShadowNode;
}
}
@@ -190,11 +190,11 @@ class ShadowNode : public Sealable,
bool progressStateIfNecessary();
/*
* Bind the runtime reference to this `ShadowNode` with a raw pointer,
* Bind the runtime reference to this `ShadowNode` with a weak pointer,
* allowing to update the reference to this `ShadowNode` when cloned.
*/
void setRuntimeShadowNodeReference(
ShadowNodeWrapper* runtimeShadowNodeReference) const;
void setRuntimeShadowNodeReference(const std::shared_ptr<ShadowNodeWrapper>&
runtimeShadowNodeReference) const;
/*
* Transfer the runtime reference to this `ShadowNode` to a new instance,
@@ -269,9 +269,9 @@ class ShadowNode : public Sealable,
ShadowNodeTraits traits_;
/*
* Pointer to the runtime reference to this `ShadowNode`.
* Weak pointer to the runtime reference to this `ShadowNode`.
*/
mutable ShadowNodeWrapper* runtimeShadowNodeReference_{};
mutable std::weak_ptr<ShadowNodeWrapper> runtimeShadowNodeReference_{};
};
static_assert(
@@ -353,7 +353,7 @@ TEST_P(ShadowNodeTest, testCloneTree) {
TEST_P(ShadowNodeTest, handleRuntimeReferenceTransferOnClone) {
auto nodeABRev1 = nodeAB_->clone({});
auto wrappedShadowNode = std::make_shared<ShadowNodeWrapper>(nodeABRev1);
nodeABRev1->setRuntimeShadowNodeReference(&*wrappedShadowNode);
nodeABRev1->setRuntimeShadowNodeReference(wrappedShadowNode);
auto nodeABRev2 = nodeABRev1->clone({});
@@ -52,7 +52,7 @@ inline static jsi::Value valueFromShadowNode(
if (assignRuntimeShadowNodeReference) {
wrappedShadowNode->shadowNode->setRuntimeShadowNodeReference(
&*wrappedShadowNode);
wrappedShadowNode);
}
jsi::Object obj(runtime);