From 3cbdbb888bae6068149b7a60476c4b1ac4d14a35 Mon Sep 17 00:00:00 2001 From: Martin Lindsay Date: Mon, 22 Feb 2021 10:57:35 -0500 Subject: [PATCH 1/2] ZSTD_seekable_decompress() example that hangs. --- .../seekable_format/tests/seekable_tests.c | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/contrib/seekable_format/tests/seekable_tests.c b/contrib/seekable_format/tests/seekable_tests.c index f2556b51..44efe2b0 100644 --- a/contrib/seekable_format/tests/seekable_tests.c +++ b/contrib/seekable_format/tests/seekable_tests.c @@ -53,6 +53,60 @@ int main(int argc, const char** argv) } printf("Success!\n"); + printf("Test %u - check that seekable decompress does not hang: ", testNb++); + { /* Github issue #FIXME */ + const size_t compressed_size = 27; + const uint8_t compressed_data[27] = { + '\x28', + '\xb5', + '\x2f', + '\xfd', + '\x00', + '\x32', + '\x91', + '\x00', + '\x00', + '\x00', + '\x5e', + '\x2a', + '\x4d', + '\x18', + '\x09', + '\x00', + '\x00', + '\x00', + '\x00', + '\x00', + '\x00', + '\x00', + '\x00', + '\xb1', + '\xea', + '\x92', + '\x8f', + }; + const size_t uncompressed_size = 8936; + uint8_t uncompressed_data[8936]; + + ZSTD_seekable* stream = ZSTD_seekable_create(); + size_t status = ZSTD_seekable_initBuff(stream, compressed_data, compressed_size); + if (ZSTD_isError(status)) { + ZSTD_seekable_free(stream); + goto _test_error; + } + + const size_t offset = 2; + /* Should return an error, but not hang */ + status = ZSTD_seekable_decompress(stream, uncompressed_data, uncompressed_size, offset); + if (!ZSTD_isError(status)) { + ZSTD_seekable_free(stream); + goto _test_error; + } + + ZSTD_seekable_free(stream); + } + printf("Success!\n"); + /* TODO: Add more tests */ printf("Finished tests\n"); return 0; From 527a20c3cdd8d5d887e82213e2aad42f050b68ce Mon Sep 17 00:00:00 2001 From: Sen Huang Date: Tue, 2 Mar 2021 14:30:03 -0800 Subject: [PATCH 2/2] Fix seekable decompress hanging --- contrib/seekable_format/tests/seekable_tests.c | 6 +++--- contrib/seekable_format/zstdseek_decompress.c | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/contrib/seekable_format/tests/seekable_tests.c b/contrib/seekable_format/tests/seekable_tests.c index 44efe2b0..2a159a31 100644 --- a/contrib/seekable_format/tests/seekable_tests.c +++ b/contrib/seekable_format/tests/seekable_tests.c @@ -53,7 +53,7 @@ int main(int argc, const char** argv) } printf("Success!\n"); - printf("Test %u - check that seekable decompress does not hang: ", testNb++); + printf("Test %u - check #2 that seekable decompress does not hang: ", testNb++); { /* Github issue #FIXME */ const size_t compressed_size = 27; const uint8_t compressed_data[27] = { @@ -85,8 +85,8 @@ int main(int argc, const char** argv) '\x92', '\x8f', }; - const size_t uncompressed_size = 8936; - uint8_t uncompressed_data[8936]; + const size_t uncompressed_size = 400; + uint8_t uncompressed_data[400]; ZSTD_seekable* stream = ZSTD_seekable_create(); size_t status = ZSTD_seekable_initBuff(stream, compressed_data, compressed_size); diff --git a/contrib/seekable_format/zstdseek_decompress.c b/contrib/seekable_format/zstdseek_decompress.c index 4f76158e..ed0880ef 100644 --- a/contrib/seekable_format/zstdseek_decompress.c +++ b/contrib/seekable_format/zstdseek_decompress.c @@ -383,6 +383,7 @@ size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsign { U32 targetFrame = ZSTD_seekable_offsetToFrameIndex(zs, offset); U32 noOutputProgressCount = 0; + size_t srcBytesRead = 0; do { /* check if we can continue from a previous decompress job */ if (targetFrame != zs->curFrame || offset != zs->decompressedOffset) { @@ -395,12 +396,16 @@ size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsign zs->in = (ZSTD_inBuffer){zs->inBuff, 0, 0}; XXH64_reset(&zs->xxhState, 0); ZSTD_DCtx_reset(zs->dstream, ZSTD_reset_session_only); + if (srcBytesRead > zs->buffWrapper.size) { + return ERROR(seekableIO); + } } while (zs->decompressedOffset < offset + len) { size_t toRead; ZSTD_outBuffer outTmp; size_t prevOutPos; + size_t prevInPos; size_t forwardProgress; if (zs->decompressedOffset < offset) { /* dummy decompressions until we get to the target offset */ @@ -410,6 +415,7 @@ size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsign } prevOutPos = outTmp.pos; + prevInPos = zs->in.pos; toRead = ZSTD_decompressStream(zs->dstream, &outTmp, &zs->in); if (ZSTD_isError(toRead)) { return toRead; @@ -428,6 +434,7 @@ size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsign noOutputProgressCount = 0; } zs->decompressedOffset += forwardProgress; + srcBytesRead += zs->in.pos - prevInPos; if (toRead == 0) { /* frame complete */