Bug #14400
closedSnappy decompressor may assert when handling segmented input bufferlist
0%
Description
The issue may occur when the first data segment in an input bufferlist for SnappyCompressor::decompress call is less then 8 bytes.
The root cause is bufferlist::get_contiguous() method call that might invalidate bufferlist iterator initialized in BufferlistSource ctor:
class BufferlistSource : public snappy::Source {
list<bufferptr>::const_iterator pb;
...
public:
BufferlistSource(bufferlist &data): pb(data.buffers().begin()), pb_off(0), left(data.length()) {}
class SnappyCompressor : public Compressor {
...
virtual int decompress(bufferlist &src, bufferlist &dst) {
BufferlistSource source(src);
size_t res_len = 0;
// Trick, decompress only need first 32bits buffer
if (snappy::GetUncompressedLength(src.get_contiguous(0, 8), 8, &res_len))
return -1;
...
Following patch for snappy compressor UT demonstrates the issue:
diff --git a/src/test/compressor/test_compression_snappy.cc b/src/test/compressor/test_compression_snappy.cc
index 69b0ebf..6768136 100644
--- a/src/test/compressor/test_compression_snappy.cc
+++ b/src/test/compressor/test_compression_snappy.cc@ -38,6 +38,39
@ TEST
EXPECT_EQ(res, 0);
}
TEST
{
+ const size_t small_prefix_size=3;
SnappyCompressor sp;
+ EXPECT_EQ(sp.get_method_name(), "snappy");
+ string test(128*1024,0);
+ int len = test.size();
+ bufferlist in, out;
+ in.append(test.c_str(), len);
+ int res = sp.compress(in, out);
+ EXPECT_EQ(res, 0);
+ EXPECT_GT(out.length(), 3u);
+
+ bufferlist out2, tmp;
+ const size_t small_prefix=3;
+ tmp.substr_of(out, 0, small_prefix_size );
+ out2.append( tmp );
+ size_t left = out.length()-small_prefix_size;
+ size_t offs = small_prefix;
+ while( left > 0 ){
+ size_t shard_size = MIN;
+ tmp.substr_of(out, offs, shard_size );
+ out2.append( tmp );
+ left -= shard_size;
+ offs = shard_size;
}
bufferlist after;
+ res = sp.decompress(out2, after);
+ EXPECT_EQ(res, 0);
}
int main(int argc, char *argv) {
vector<const char> args;
argv_to_vec(argc, (const char **)argv, args);