Fix data corruption when output of snappy compression is more than 4GB
This fixes #201
This commit is contained in:
@@ -1499,7 +1499,7 @@ class SnappyDecompressor {
|
|||||||
// If ip < ip_limit_min_maxtaglen_ it's safe to read kMaxTagLength from
|
// If ip < ip_limit_min_maxtaglen_ it's safe to read kMaxTagLength from
|
||||||
// buffer.
|
// buffer.
|
||||||
const char* ip_limit_min_maxtaglen_;
|
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?
|
bool eof_; // Hit end of input without an error?
|
||||||
char scratch_[kMaximumTagLength]; // See RefillTag().
|
char scratch_[kMaximumTagLength]; // See RefillTag().
|
||||||
|
|
||||||
@@ -1726,7 +1726,7 @@ bool SnappyDecompressor::RefillTag() {
|
|||||||
assert(needed <= sizeof(scratch_));
|
assert(needed <= sizeof(scratch_));
|
||||||
|
|
||||||
// Read more bytes from reader if needed
|
// Read more bytes from reader if needed
|
||||||
uint32_t nbuf = ip_limit_ - ip;
|
uint64_t nbuf = ip_limit_ - ip;
|
||||||
if (nbuf < needed) {
|
if (nbuf < needed) {
|
||||||
// Stitch together bytes from ip and reader to form the word
|
// Stitch together bytes from ip and reader to form the word
|
||||||
// contents. We store the needed bytes in "scratch_". They
|
// contents. We store the needed bytes in "scratch_". They
|
||||||
@@ -1739,7 +1739,7 @@ bool SnappyDecompressor::RefillTag() {
|
|||||||
size_t length;
|
size_t length;
|
||||||
const char* src = reader_->Peek(&length);
|
const char* src = reader_->Peek(&length);
|
||||||
if (length == 0) return false;
|
if (length == 0) return false;
|
||||||
uint32_t to_add = std::min<uint32_t>(needed - nbuf, length);
|
uint64_t to_add = std::min<uint64_t>(needed - nbuf, length);
|
||||||
std::memcpy(scratch_ + nbuf, src, to_add);
|
std::memcpy(scratch_ + nbuf, src, to_add);
|
||||||
nbuf += to_add;
|
nbuf += to_add;
|
||||||
reader_->Skip(to_add);
|
reader_->Skip(to_add);
|
||||||
@@ -1802,6 +1802,7 @@ size_t Compress(Source* reader, Sink* writer, CompressionOptions options) {
|
|||||||
int token = 0;
|
int token = 0;
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
size_t N = reader->Available();
|
size_t N = reader->Available();
|
||||||
|
assert(N <= 0xFFFFFFFFu);
|
||||||
const size_t uncompressed_size = N;
|
const size_t uncompressed_size = N;
|
||||||
char ulength[Varint::kMax32];
|
char ulength[Varint::kMax32];
|
||||||
char* p = Varint::Encode32(ulength, N);
|
char* p = Varint::Encode32(ulength, N);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cinttypes>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -484,6 +485,18 @@ TEST(Snappy, MaxBlowup) {
|
|||||||
Verify(input);
|
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<int> 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<char>(uniform_byte(rng));
|
||||||
|
Verify(input);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Snappy, RandomData) {
|
TEST(Snappy, RandomData) {
|
||||||
std::minstd_rand0 rng(snappy::GetFlag(FLAGS_test_random_seed));
|
std::minstd_rand0 rng(snappy::GetFlag(FLAGS_test_random_seed));
|
||||||
std::uniform_int_distribution<int> uniform_0_to_3(0, 3);
|
std::uniform_int_distribution<int> uniform_0_to_3(0, 3);
|
||||||
|
|||||||
Reference in New Issue
Block a user