Add property-based fuzz tests for QuicInlinedStringView
PiperOrigin-RevId: 770154077
diff --git a/build/source_list.bzl b/build/source_list.bzl
index 1c01d4a..0bbd9b2 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -1316,6 +1316,7 @@
"quic/core/quic_framer_test.cc",
"quic/core/quic_generic_session_test.cc",
"quic/core/quic_idle_network_detector_test.cc",
+ "quic/core/quic_inlined_string_view_fuzz_test.cc",
"quic/core/quic_inlined_string_view_test.cc",
"quic/core/quic_interval_deque_test.cc",
"quic/core/quic_interval_set_test.cc",
diff --git a/build/source_list.gni b/build/source_list.gni
index 5ca530c..54bbd26 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -1317,6 +1317,7 @@
"src/quiche/quic/core/quic_framer_test.cc",
"src/quiche/quic/core/quic_generic_session_test.cc",
"src/quiche/quic/core/quic_idle_network_detector_test.cc",
+ "src/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc",
"src/quiche/quic/core/quic_inlined_string_view_test.cc",
"src/quiche/quic/core/quic_interval_deque_test.cc",
"src/quiche/quic/core/quic_interval_set_test.cc",
diff --git a/build/source_list.json b/build/source_list.json
index f35ce33..9830675 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -1316,6 +1316,7 @@
"quiche/quic/core/quic_framer_test.cc",
"quiche/quic/core/quic_generic_session_test.cc",
"quiche/quic/core/quic_idle_network_detector_test.cc",
+ "quiche/quic/core/quic_inlined_string_view_fuzz_test.cc",
"quiche/quic/core/quic_inlined_string_view_test.cc",
"quiche/quic/core/quic_interval_deque_test.cc",
"quiche/quic/core/quic_interval_set_test.cc",
diff --git a/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc b/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc
new file mode 100644
index 0000000..d330853
--- /dev/null
+++ b/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc
@@ -0,0 +1,107 @@
+// Copyright 2025 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cstddef>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/quic_inlined_string_view.h"
+#include "quiche/quic/core/quic_stream_send_buffer_inlining.h"
+#include "quiche/common/platform/api/quiche_fuzztest.h"
+#include "quiche/common/platform/api/quiche_test.h"
+
+namespace quic {
+namespace {
+
+// Defines methods that test properties of `QuicInlinedStringView<kSize>`.
+template <size_t kSize>
+class Properties {
+ public:
+ static void AccessorsAreCorrect(absl::string_view view) {
+ QuicInlinedStringView<kSize> quic_view(view);
+
+ // Copying the memory that `quic_view` points to enables ASAN to catch
+ // out-of-bounds accesses.
+ std::string copy(quic_view.view());
+
+ EXPECT_EQ(quic_view.empty(), view.empty());
+ EXPECT_EQ(quic_view.size(), view.size());
+ EXPECT_EQ(quic_view.view(), view);
+ EXPECT_EQ(quic_view.IsInlined(), view.size() < kSize);
+
+ QuicInlinedStringView<kSize> quic_view_copy(quic_view);
+ EXPECT_EQ(quic_view_copy.empty(), view.empty());
+ EXPECT_EQ(quic_view_copy.size(), view.size());
+ EXPECT_EQ(quic_view_copy.view(), view);
+ EXPECT_EQ(quic_view_copy.IsInlined(), view.size() < kSize);
+ }
+
+ static void IsEmptyAfterClear(absl::string_view view) {
+ QuicInlinedStringView<kSize> quic_view(view);
+ quic_view.clear();
+ EXPECT_TRUE(quic_view.empty());
+ }
+
+ static void DifferentDataPointersWhenInlined(absl::string_view view) {
+ QuicInlinedStringView<kSize> quic_view(view);
+ if (!quic_view.empty()) {
+ const bool pointers_equal = view.data() == quic_view.data();
+ EXPECT_EQ(!pointers_equal, quic_view.IsInlined());
+ } else {
+ EXPECT_EQ(quic_view.data(), nullptr);
+ }
+ }
+};
+
+// Below, we fuzz each property with different values of `kSize`.
+// - The value of 16 matches the `kSize` used by `BufferedSliceInlining`.
+// - The value of 24 was chosen to demonstrate that these properties hold for at
+// least one other value.
+// - The value of 254 was chosen because it's the largest value supported by
+// `QuicInlinedStringView`.
+constexpr size_t kRealisticSize =
+ decltype(BufferedSliceInlining::slice)::kMaxInlinedSize + 1;
+static_assert(kRealisticSize == 16);
+
+void NeverCrashes16(absl::string_view view) {
+ Properties<16>::AccessorsAreCorrect(view);
+}
+void NeverCrashes24(absl::string_view view) {
+ Properties<24>::AccessorsAreCorrect(view);
+}
+void NeverCrashes254(absl::string_view view) {
+ Properties<254>::AccessorsAreCorrect(view);
+}
+FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes16);
+FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes24);
+FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes254);
+
+void IsEmptyAfterClear16(absl::string_view view) {
+ Properties<16>::IsEmptyAfterClear(view);
+}
+void IsEmptyAfterClear24(absl::string_view view) {
+ Properties<24>::IsEmptyAfterClear(view);
+}
+void IsEmptyAfterClear254(absl::string_view view) {
+ Properties<254>::IsEmptyAfterClear(view);
+}
+FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear16);
+FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear24);
+FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear254);
+
+void DifferentDataPointersWhenInlined16(absl::string_view view) {
+ Properties<16>::DifferentDataPointersWhenInlined(view);
+}
+void DifferentDataPointersWhenInlined24(absl::string_view view) {
+ Properties<24>::DifferentDataPointersWhenInlined(view);
+}
+void DifferentDataPointersWhenInlined254(absl::string_view view) {
+ Properties<254>::DifferentDataPointersWhenInlined(view);
+}
+FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined16);
+FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined24);
+FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined254);
+
+} // namespace
+} // namespace quic