Fix the packed length prefix and over-encoded zero in binary_wireformat. Packed() prefixed its payload with the element count instead of the byte length, which only matches the wire format when every element is a single byte. LongVarint(0, n) returned a plain zero byte, ignoring the requested over-encoding, and the bounds check guarding its stack buffer compiled out in optimized builds. The unit tests that enshrined the wrong bytes are corrected and new cases pin the length-vs-count distinction. PiperOrigin-RevId: 1002052455
diff --git a/conformance/BUILD b/conformance/BUILD index c209321..efcaa34 100644 --- a/conformance/BUILD +++ b/conformance/BUILD
@@ -314,6 +314,7 @@ deps = [ "//src/google/protobuf:endian", "//src/google/protobuf:protobuf_lite", + "@abseil-cpp//absl/log:absl_check", "@abseil-cpp//absl/strings", ], )
diff --git a/conformance/binary_wireformat.cc b/conformance/binary_wireformat.cc index 3ed5f4a..3921f94 100644 --- a/conformance/binary_wireformat.cc +++ b/conformance/binary_wireformat.cc
@@ -1,10 +1,10 @@ #include "conformance/binary_wireformat.h" -#include <cassert> #include <cstdint> #include <cstring> #include <string> +#include "absl/log/absl_check.h" #include "absl/strings/string_view.h" #include "google/protobuf/endian.h" #include "google/protobuf/wire_format_lite.h" @@ -18,19 +18,16 @@ #define VARINT_MAX_LEN 10 size_t vencode64(uint64_t val, int over_encoded_bytes, char* buf) { - if (val == 0) { - buf[0] = 0; - return 1; - } + ABSL_CHECK_GE(over_encoded_bytes, 0); size_t i = 0; - while (val) { + do { uint8_t byte = val & 0x7fU; val >>= 7; if (val || over_encoded_bytes) byte |= 0x80U; buf[i++] = byte; - } + } while (val); while (over_encoded_bytes--) { - assert(i < 10); + ABSL_CHECK_LT(i, VARINT_MAX_LEN); uint8_t byte = over_encoded_bytes ? 0x80 : 0; buf[i++] = byte; }
diff --git a/conformance/binary_wireformat.h b/conformance/binary_wireformat.h index 63c5f7b..86f01eb 100644 --- a/conformance/binary_wireformat.h +++ b/conformance/binary_wireformat.h
@@ -169,11 +169,11 @@ namespace internal { template <typename Func, typename Container> Wire PackedImpl(Func func, const Container& container) { - std::string buf = Varint(container.size()).str(); + std::string elements; for (auto x : container) { - absl::StrAppend(&buf, func(x).str()); + absl::StrAppend(&elements, func(x).str()); } - return Wire(buf); + return LengthPrefixed(elements); } } // namespace internal
diff --git a/conformance/binary_wireformat_test.cc b/conformance/binary_wireformat_test.cc index 5e5d322..f285d96 100644 --- a/conformance/binary_wireformat_test.cc +++ b/conformance/binary_wireformat_test.cc
@@ -148,7 +148,8 @@ INSTANTIATE_TEST_SUITE_P( LongVarintTest, LongVarintTest, testing::ValuesIn(std::vector<LongVarintTestCase>{ - {0, 1, std::string("\000", 1)}, + {0, 1, std::string("\200\000", 2)}, + {0, 2, std::string("\200\200\000", 3)}, {1, 1, std::string("\201\000", 2)}, {1, 4, std::string("\201\200\200\200\000", 5)}, {127, 1, std::string("\377\000", 2)}, @@ -347,7 +348,16 @@ TEST(PackedTest, OneFixed32) { EXPECT_EQ(Packed(Fixed32<int>, {9}), - Wire(absl::string_view("\001\011\000\000\000", 5))); + Wire(absl::string_view("\004\011\000\000\000", 5))); +} + +TEST(PackedTest, TwoFixed32s) { + EXPECT_EQ(Packed(Fixed32<int>, {9, 8}), + Wire(absl::string_view("\010\011\000\000\000\010\000\000\000", 9))); +} + +TEST(PackedTest, MultiByteVarints) { + EXPECT_EQ(Packed(Varint<int>, {128, 1}), Wire("\003\200\001\001")); } TEST(PackedTest, Varints) {