From 67e34583506fe742f7c4562d4ebf4f0b2337c38a Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Thu, 9 Apr 2026 10:31:37 -0700 Subject: [PATCH] Fix crash in PerformanceEntrySorter comparator (#56388) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/56388 Fixed a SIGSEGV crash in the Performance API that occurred when sorting performance entries. The crash was caused by the PerformanceEntrySorter comparator missing the const qualifier on its operator() method. The PerformanceEntrySorter::operator() was not marked as const, which violates the requirements for comparators used with std::stable_sort. This caused undefined behavior and crashes on Android when sorting performance entries. Added the const qualifier to PerformanceEntrySorter::operator()() to ensure it's properly const-qualified for use with STL sorting algorithms. Changelog: [General][Fixed] - Fix crash in Performance API when sorting entries Reviewed By: rubennorte Differential Revision: D98674156 --- .../performance/timeline/PerformanceEntry.h | 2 +- .../timeline/tests/PerformanceEntryTest.cpp | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryTest.cpp diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h index 1b7275352173..291bb2ace829 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h @@ -80,7 +80,7 @@ using PerformanceEntry = std::variant< PerformanceResourceTiming>; struct PerformanceEntrySorter { - bool operator()(const PerformanceEntry &lhs, const PerformanceEntry &rhs) + bool operator()(const PerformanceEntry &lhs, const PerformanceEntry &rhs) const { return std::visit( [](const auto &left, const auto &right) { diff --git a/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryTest.cpp b/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryTest.cpp new file mode 100644 index 000000000000..b6c6d7f9205d --- /dev/null +++ b/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryTest.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include + +#include "../PerformanceEntry.h" + +using namespace facebook::react; + +// Verify that PerformanceEntrySorter::operator() is const-qualified. +// Without const, std::stable_sort may fail to compile on toolchains where +// the comparator is passed through a const-qualified code path (e.g. +// libc++ __insertion_sort on NDK 19.x), causing SIGSEGV at runtime on +// others. See T263807207. +TEST(PerformanceEntry, SorterOperatorIsConst) { + static_assert( + std::is_invocable_v< + const PerformanceEntrySorter, + const PerformanceEntry&, + const PerformanceEntry&>, + "PerformanceEntrySorter::operator() must be const-qualified"); +} + +TEST(PerformanceEntry, SortEntriesByStartTimeThenDuration) { + auto t0 = HighResTimeStamp::now(); + auto t1 = t0 + HighResDuration::fromMilliseconds(1); + auto t2 = t0 + HighResDuration::fromMilliseconds(2); + + std::vector entries = { + PerformanceMark{{.name = "c", .startTime = t2}}, + PerformanceMark{{.name = "a", .startTime = t0}}, + PerformanceMeasure{ + {.name = "b", + .startTime = t0, + .duration = HighResDuration::fromMilliseconds(5)}}, + PerformanceMark{ + {.name = "d", .startTime = t1, .duration = HighResDuration::zero()}}, + }; + + std::stable_sort(entries.begin(), entries.end(), PerformanceEntrySorter{}); + + // Entries with same startTime are ordered by duration (ascending). + // "a" (t0, dur=0) < "b" (t0, dur=5) < "d" (t1, dur=0) < "c" (t2, dur=0) + ASSERT_EQ(4, entries.size()); + + auto getName = [](const PerformanceEntry& e) { + return std::visit([](const auto& x) { return x.name; }, e); + }; + + EXPECT_EQ("a", getName(entries[0])); + EXPECT_EQ("b", getName(entries[1])); + EXPECT_EQ("d", getName(entries[2])); + EXPECT_EQ("c", getName(entries[3])); +}