Skip to content

fix: UB when upcasting yoga sentinel value - #57761

Open
tjzel wants to merge 2 commits into
react:mainfrom
tjzel:yoga-ubsan-sentinel-fix
Open

fix: UB when upcasting yoga sentinel value#57761
tjzel wants to merge 2 commits into
react:mainfrom
tjzel:yoga-ubsan-sentinel-fix

Conversation

@tjzel

@tjzel tjzel commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary:

Fixing Undefined Behavior found with UB sanitizer ran against a React Native app.

Yoga always upcasts the node address, even if it is a sentinel value 0xbadc0ffee0ddf00d.

UB sanitizer log

[runtime-tests] 1 sanitizer report file(s):
--- ubsan.9142 ---
/Users/runner/work/react-native-reanimated/react-native-reanimated/node_modules/react-native/ReactCommon/yoga/yoga/YGNode.cpp:282:10: runtime error: upcast of misaligned address 0xbadc0ffee0ddf00d for type 'facebook::yoga::Node', which requires 8 byte alignment
0xbadc0ffee0ddf00d: note: pointer points here
<memory cannot be printed>
    #0 0x000103e9578c in YGNodeGetOwner YGNode.cpp:282
    #1 0x00010381f028 in facebook::react::YogaLayoutableShadowNode::updateYogaChildrenOwnersIfNeeded() YogaLayoutableShadowNode.cpp:344
    #2 0x00010381ebdc in facebook::react::YogaLayoutableShadowNode::YogaLayoutableShadowNode(facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&) YogaLayoutableShadowNode.cpp:130
    #3 0x0001037e4e2c in facebook::react::ConcreteViewShadowNode<&facebook::react::ViewComponentName, facebook::react::BaseViewProps, facebook::react::BaseViewEventEmitter, facebook::react::StateData>::ConcreteViewShadowNode(facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&) ConcreteViewShadowNode.h:59
    #4 0x0001037e4d88 in facebook::react::ViewShadowNode::ViewShadowNode(facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&) ViewShadowNode.cpp:28
    #5 0x000103b25cf0 in std::__1::__shared_ptr_emplace<facebook::react::ViewShadowNode, std::__1::allocator<facebook::react::ViewShadowNode>>::__shared_ptr_emplace[abi:nqe210106]<facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&, std::__1::allocator<facebook::react::ViewShadowNode>, 0>(std::__1::allocator<facebook::react::ViewShadowNode>, facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&) shared_ptr.h:162
    #6 0x000103b25af0 in std::__1::shared_ptr<facebook::react::ViewShadowNode> std::__1::allocate_shared[abi:nqe210106]<facebook::react::ViewShadowNode, std::__1::allocator<facebook::react::ViewShadowNode>, facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&, 0>(std::__1::allocator<facebook::react::ViewShadowNode> const&, facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&) shared_ptr.h:736
    #7 0x000103b23858 in facebook::react::ConcreteComponentDescriptor<facebook::react::ViewShadowNode>::cloneShadowNode(facebook::react::ShadowNode const&, facebook::react::ShadowNodeFragment const&) const ConcreteComponentDescriptor.h:94
    #8 0x00010371c614 in facebook::react::ShadowNode::clone(facebook::react::ShadowNodeFragment const&) const ShadowNode.cpp:168
    #9 0x00010381f6f8 in facebook::react::YogaLayoutableShadowNode::adoptYogaChild(unsigned long) YogaLayoutableShadowNode.cpp:214
    #10 0x00010381fb74 in facebook::react::YogaLayoutableShadowNode::appendChild(std::__1::shared_ptr<facebook::react::ShadowNode const> const&) YogaLayoutableShadowNode.cpp:252
    #11 0x0001037806c8 in facebook::react::UIManager::appendChild(std::__1::shared_ptr<facebook::react::ShadowNode const> const&, std::__1::shared_ptr<facebook::react::ShadowNode const> const&) const UIManager.cpp:188
    #12 0x0001037b13f8 in std::__1::__function::__func<facebook::react::UIManagerBinding::get(facebook::jsi::Runtime&, facebook::jsi::PropNameID const&)::$_6, facebook::jsi::Value (facebook::jsi::Runtime&, facebook::jsi::Value const&, facebook::jsi::Value const*, unsigned long)>::operator()(facebook::jsi::Runtime&, facebook::jsi::Value const&, facebook::jsi::Value const*&&, unsigned long&&) function.h:174
    #13 0x00010856d8c0 in std::__1::function<facebook::jsi::Value (facebook::jsi::Runtime&, facebook::jsi::Value const&, facebook::jsi::Value const*, unsigned long)>::operator()(facebook::jsi::Runtime&, facebook::jsi::Value const&, facebook::jsi::Value const*, unsigned long) const+0x28 (hermesvm:arm64+0x298c0)
    #14 0x00010856d5f8 in facebook::hermes::(anonymous namespace)::HermesRuntimeImpl::HFContext::func(void*, hermes::vm::Runtime&)+0xd4 (hermesvm:arm64+0x295f8)
    #15 0x000108642d5c in hermes::vm::NativeFunction::_nativeCall(hermes::vm::NativeFunction*, hermes::vm::Runtime&)+0x3c (hermesvm:arm64+0xfed5c)
    #16 0x00010864d5d4 in hermes::vm::Interpreter::handleCallSlowPath(hermes::vm::Runtime&, hermes::vm::PinnedHermesValue*)+0x5c (hermesvm:arm64+0x1095d4)
    #17 0x00010864f910 in hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::Interpreter::interpretFunction<false, false>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)+0x22dc (hermesvm:arm64+0x10b910)
    #18 0x0001086e80e0 in hermes::vm::Runtime::interpretFunctionImpl(hermes::vm::CodeBlock*)+0x30 (hermesvm:arm64+0x1a40e0)
    #19 0x000108642e20 in hermes::vm::JSFunction::_callImpl(hermes::vm::Handle<hermes::vm::Callable>, hermes::vm::Runtime&)+0x1c (hermesvm:arm64+0xfee20)
    #20 0x0001086426c4 in hermes::vm::BoundFunction::_boundCall(hermes::vm::BoundFunction*, hermes::vm::Runtime&)+0x180 (hermesvm:arm64+0xfe6c4)
    #21 0x0001085650fc in facebook::hermes::(anonymous namespace)::HermesRuntimeImpl::call(facebook::jsi::Function const&, facebook::jsi::Value const&, facebook::jsi::Value const*, unsigned long)+0x118 (hermesvm:arm64+0x210fc)
    #22 0x000103db8ffc in facebook::react::Task::execute(facebook::jsi::Runtime&, bool) Task.cpp:57
    #23 0x000103da1704 in facebook::react::RuntimeScheduler_Modern::executeTask(facebook::jsi::Runtime&, facebook::react::Task&, bool) RuntimeScheduler_Modern.cpp:392
    #24 0x000103da2ca4 in facebook::react::RuntimeScheduler_Modern::runEventLoopTick(facebook::jsi::Runtime&, facebook::react::Task&) RuntimeScheduler_Modern.cpp:329
    #25 0x000103da2568 in facebook::react::RuntimeScheduler_Modern::runEventLoop(facebook::jsi::Runtime&) RuntimeScheduler_Modern.cpp:283
    #26 0x000103bb59c0 in _ZNSt3__110__function6__funcIZZN8facebook5react13ReactInstanceC1ENS_10unique_ptrINS3_9JSRuntimeENS_14default_deleteIS6_EEEENS_10shared_ptrINS3_18MessageQueueThreadEEENSA_INS3_12TimerManagerEEENS_8functionIFvRNS2_3jsi7RuntimeERKNS3_14JsErrorHandler14ProcessedErrorEEEEPNS3_18jsinspector_modern10HostTargetEENK3$_0clINSF_IFvSI_EEEEEDaT_EUlvE_FvvEEclEv function.h:174
    #27 0x000103238784 in facebook::react::tryAndReturnError(std::__1::function<void ()> const&) RCTCxxUtils.mm:50
    #28 0x00010325a524 in facebook::react::RCTMessageThread::tryFunc(std::__1::function<void ()> const&) RCTMessageThread.mm:68
    #29 0x00010325a00c in invocation function for block in facebook::react::RCTMessageThread::runAsync(std::__1::function<void ()>) RCTMessageThread.mm:44
    #30 0x000180420750 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__+0x10 (CoreFoundation:arm64+0x93750)
    #31 0x00018041fedc in __CFRunLoopDoBlocks+0x150 (CoreFoundation:arm64+0x92edc)
    #32 0x00018041f820 in __CFRunLoopRun+0x8e4 (CoreFoundation:arm64+0x92820)
    #33 0x00018041a32c in _CFRunLoopRunSpecificWithOptions+0x1ec (CoreFoundation:arm64+0x8d32c)
    #34 0x000103ba0d28 in +[RCTJSThreadManager runRunLoop] RCTJSThreadManager.mm:102
    #35 0x00018112cf48 in __NSThread__start__+0x2c8 (Foundation:arm64+0x8eff48)
    #36 0x000108a56930 in asan_thread_start(void*)+0x48 (libclang_rt.asan_iossim_dynamic.dylib:arm64+0x3a930)
    #37 0x0001077aa638 in _pthread_start+0x64 (libsystem_pthread.dylib:arm64+0x6638)
    #38 0x0001077a5a30 in thread_start+0x4 (libsystem_pthread.dylib:arm64+0x1a30)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/runner/work/react-native-reanimated/react-native-reanimated/node_modules/react-native/ReactCommon/yoga/yoga/YGNode.cpp:282:10 

========================================

Changelog:

[INTERNAL] [FIXED] - UB when upcasting yoga sentinel value

Test Plan:

UBsan no longer complains.

@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 30, 2026
@facebook-github-tools facebook-github-tools Bot added p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels Jul 30, 2026
@javache

javache commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Upcasting from yoga::Node* to YGNodeRef is done across the yoga codebase, so it's weird to diverge here.

Maybe just make kDetachedYogaNodeOwnerSentinel an 8-byte aligned pointer?

@tjzel

tjzel commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@javache Done

@meta-codesync

meta-codesync Bot commented Jul 30, 2026

Copy link
Copy Markdown

@fabriziocucci has imported this pull request. If you are a Meta employee, you can view this in D114202767.

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. p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants