From ec20182d262901f6ceb4f3f8a3ff3f70cd441445 Mon Sep 17 00:00:00 2001 From: Danila Kutenin Date: Thu, 27 Mar 2025 07:59:41 +0000 Subject: [PATCH] zippy: Fix data corruption when compressed output is more than 4GB PiperOrigin-RevId: 741053848 --- snappy.cc | 7 ++++--- snappy_unittest.cc | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/snappy.cc b/snappy.cc index c1618d4..eb9464f 100644 --- a/snappy.cc +++ b/snappy.cc @@ -1496,7 +1496,7 @@ class SnappyDecompressor { // If ip < ip_limit_min_maxtaglen_ it's safe to read kMaxTagLength from // buffer. const char* ip_limit_min_maxtaglen_; - uint32_t peeked_; // Bytes peeked from reader (need to skip) + uint64_t peeked_; // Bytes peeked from reader (need to skip) bool eof_; // Hit end of input without an error? char scratch_[kMaximumTagLength]; // See RefillTag(). @@ -1723,7 +1723,7 @@ bool SnappyDecompressor::RefillTag() { assert(needed <= sizeof(scratch_)); // Read more bytes from reader if needed - uint32_t nbuf = ip_limit_ - ip; + uint64_t nbuf = ip_limit_ - ip; if (nbuf < needed) { // Stitch together bytes from ip and reader to form the word // contents. We store the needed bytes in "scratch_". They @@ -1736,7 +1736,7 @@ bool SnappyDecompressor::RefillTag() { size_t length; const char* src = reader_->Peek(&length); if (length == 0) return false; - uint32_t to_add = std::min(needed - nbuf, length); + uint64_t to_add = std::min(needed - nbuf, length); std::memcpy(scratch_ + nbuf, src, to_add); nbuf += to_add; reader_->Skip(to_add); @@ -1794,6 +1794,7 @@ size_t Compress(Source* reader, Sink* writer, CompressionOptions options) { int snappy_token = 0; size_t written = 0; size_t N = reader->Available(); + assert(N <= 0xFFFFFFFFu); const size_t uncompressed_size = N; char ulength[Varint::kMax32]; char* p = Varint::Encode32(ulength, N); diff --git a/snappy_unittest.cc b/snappy_unittest.cc index e57b13d..923a0ec 100644 --- a/snappy_unittest.cc +++ b/snappy_unittest.cc @@ -27,6 +27,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include #include #include @@ -484,6 +485,18 @@ TEST(Snappy, MaxBlowup) { Verify(input); } +// Issue #201, when output is more than 4GB, we had a data corruption bug. +// We cannot run this test always because of CI constraints. +TEST(Snappy, DISABLED_MoreThan4GB) { + std::mt19937 rng; + std::uniform_int_distribution uniform_byte(0, 255); + std::string input; + input.resize((1ull << 32) - 1); + for (uint64_t i = 0; i < ((1ull << 32) - 1); ++i) + input[i] = static_cast(uniform_byte(rng)); + Verify(input); +} + TEST(Snappy, RandomData) { std::minstd_rand0 rng(snappy::GetFlag(FLAGS_test_random_seed)); std::uniform_int_distribution uniform_0_to_3(0, 3);