PUBLIC: Add a fuzz test for parsing and serializing quic versions

This fuzzer immediately found an undefined enum cast in ParseQuicVersionString(). This CL fixes that cast and adds a non-fuzz regression test.

PiperOrigin-RevId: 772473029
diff --git a/quiche/quic/core/quic_versions.cc b/quiche/quic/core/quic_versions.cc
index 69069ac..f27a5ef 100644
--- a/quiche/quic/core/quic_versions.cc
+++ b/quiche/quic/core/quic_versions.cc
@@ -386,7 +386,8 @@
   }
   int quic_version_number = 0;
   if (absl::SimpleAtoi(version_string, &quic_version_number) &&
-      quic_version_number > 0) {
+      quic_version_number > 0 &&
+      quic_version_number <= QuicTransportVersion::QUIC_VERSION_MAX_VALUE) {
     QuicTransportVersion transport_version =
         static_cast<QuicTransportVersion>(quic_version_number);
     if (!ParsedQuicVersionIsValid(PROTOCOL_QUIC_CRYPTO, transport_version)) {
diff --git a/quiche/quic/core/quic_versions.h b/quiche/quic/core/quic_versions.h
index 682e79a..f8fe6ed 100644
--- a/quiche/quic/core/quic_versions.h
+++ b/quiche/quic/core/quic_versions.h
@@ -136,6 +136,7 @@
   // version negotiation when proposed by clients and to prevent client
   // ossification when sent by servers.
   QUIC_VERSION_RESERVED_FOR_NEGOTIATION = 999,
+  QUIC_VERSION_MAX_VALUE = QUIC_VERSION_RESERVED_FOR_NEGOTIATION,
 };
 
 // Helper function which translates from a QuicTransportVersion to a string.
diff --git a/quiche/quic/core/quic_versions_test.cc b/quiche/quic/core/quic_versions_test.cc
index 5d2bfaa..2a29895 100644
--- a/quiche/quic/core/quic_versions_test.cc
+++ b/quiche/quic/core/quic_versions_test.cc
@@ -6,12 +6,16 @@
 
 #include <cstddef>
 #include <sstream>
+#include <string>
 
 #include "absl/algorithm/container.h"
 #include "absl/base/macros.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
 #include "quiche/quic/platform/api/quic_expect_bug.h"
 #include "quiche/quic/platform/api/quic_flags.h"
 #include "quiche/quic/platform/api/quic_test.h"
+#include "quiche/common/platform/api/quiche_fuzztest.h"
 
 namespace quic {
 namespace test {
@@ -353,6 +357,23 @@
   EXPECT_EQ("0,Q046", os.str());
 }
 
+void ParseSerializeParseIdentityProperty(absl::string_view input) {
+  ParsedQuicVersionVector parsed = ParseQuicVersionVectorString(input);
+  std::string serialized = ParsedQuicVersionVectorToString(parsed);
+  ParsedQuicVersionVector parsed2 = ParseQuicVersionVectorString(serialized);
+  EXPECT_EQ(parsed, parsed2);
+}
+FUZZ_TEST(QuicVersionsFuzzTest, ParseSerializeParseIdentityProperty);
+
+// Regression test for an invalid enum cast to `QuicTransportVersion` in
+// `ParseQuicVersionString()`, detected by UndefinedBehaviorSanitizer.
+TEST(QuicVersionsTest, ParseSerializeParseIdentityPropertyRegression) {
+  static constexpr int kInvalidVersion = 99999;
+  static_assert(kInvalidVersion > QuicTransportVersion::QUIC_VERSION_MAX_VALUE);
+  EXPECT_EQ(UnsupportedQuicVersion(),
+            ParseQuicVersionString(absl::StrCat(kInvalidVersion)));
+}
+
 TEST(QuicVersionsTest, FilterSupportedVersionsAllVersions) {
   for (const ParsedQuicVersion& version : AllSupportedVersions()) {
     QuicEnableVersion(version);