diff --git a/contrib/seekable_format/tests/seekable_tests.c b/contrib/seekable_format/tests/seekable_tests.c index 658b356d..af851dd6 100644 --- a/contrib/seekable_format/tests/seekable_tests.c +++ b/contrib/seekable_format/tests/seekable_tests.c @@ -56,6 +56,60 @@ int main(int argc, const char** argv) } printf("Success!\n"); + 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] = { + '\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 = 400; + uint8_t uncompressed_data[400]; + + 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; diff --git a/contrib/seekable_format/zstdseek_decompress.c b/contrib/seekable_format/zstdseek_decompress.c index 6cb9e03f..71d70c02 100644 --- a/contrib/seekable_format/zstdseek_decompress.c +++ b/contrib/seekable_format/zstdseek_decompress.c @@ -435,6 +435,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) { @@ -448,12 +449,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 */ @@ -463,6 +468,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; @@ -481,6 +487,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 */