From 3e2640df883872f00bed3981543dd87acea8aa46 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 13 May 2024 11:00:50 -0700 Subject: [PATCH] Sanitize measure function results Summary: We've started seeing assertion failures in Yoga where a `NaN` value makes its way to an `availableHeight` constraint when measuring Litho tree. Because it's only happening on Litho, I have some suspicion this might be originating from a Litho-specific measure function. This adds sanitization in Yoga to measure function results, where we will log an error, and set size to zero, if either dimension ends up being negative of `NaN`. This doesn't really help track down where the error was happening, but Yoga doesn't have great context to show this to begin with. If we see this is issue, next steps would be Litho internal intrumentation to find culprit. Changelog: [Internal] Differential Revision: D57285584 --- .../ReactCommon/yoga/yoga/node/Node.cpp | 26 ++++++++++++++++--- .../ReactCommon/yoga/yoga/node/Node.h | 4 +-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp index adb63663bed9b5..d0a5567a6b432a 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -49,12 +50,29 @@ Node::Node(Node&& node) noexcept } YGSize Node::measure( - float width, + float availableWidth, MeasureMode widthMode, - float height, + float availableHeight, MeasureMode heightMode) { - return measureFunc_( - this, width, unscopedEnum(widthMode), height, unscopedEnum(heightMode)); + const auto size = measureFunc_( + this, + availableWidth, + unscopedEnum(widthMode), + availableHeight, + unscopedEnum(heightMode)); + + if (yoga::isUndefined(size.height) || size.height < 0 || + yoga::isUndefined(size.width) || size.width < 0) { + yoga::log( + this, + LogLevel::Error, + "Measure function returned an invalid dimension to Yoga: [width=%f, height=%f]", + size.width, + size.height); + return {.width = 0.0f, .height = 0.0f}; + } + + return size; } float Node::baseline(float width, float height) const { diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h index 8f5ee591cc59e6..cd029b40d46671 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h @@ -66,9 +66,9 @@ class YG_EXPORT Node : public ::YGNode { } YGSize measure( - float width, + float availableWidth, MeasureMode widthMode, - float height, + float availableHeight, MeasureMode heightMode); bool hasBaselineFunc() const noexcept {