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);