diff options
author | Lasse Collin <lasse.collin@tukaani.org> | 2022-04-05 12:24:57 +0300 |
---|---|---|
committer | Lasse Collin <lasse.collin@tukaani.org> | 2022-04-05 12:24:57 +0300 |
commit | 64b6d496dc815a176d8307f418f6834a26783484 (patch) | |
tree | 80f122f8fe678a77fe0f6347b75c5b7d1df54b07 | |
parent | liblzma: Threaded decoder: Support zpipe.c-style decoding loop. (diff) | |
download | xz-64b6d496dc815a176d8307f418f6834a26783484.tar.xz |
liblzma: Threaded decoder: Always wait for output if LZMA_FINISH is used.
This makes the behavior consistent with the single-threaded
decoder when handling truncated .xz files.
Thanks to Jia Tan for finding this issue.
-rw-r--r-- | src/liblzma/common/stream_decoder_mt.c | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/src/liblzma/common/stream_decoder_mt.c b/src/liblzma/common/stream_decoder_mt.c index 47433de8..7f445982 100644 --- a/src/liblzma/common/stream_decoder_mt.c +++ b/src/liblzma/common/stream_decoder_mt.c @@ -1000,8 +1000,30 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, // if they assume that output-not-full implies that all input has // been consumed. If and only if timeout is enabled, we may return // when output isn't full *and* not all input has been consumed. - const bool waiting_allowed = *in_pos == in_size - && !coder->out_was_filled; + // + // However, if LZMA_FINISH is used, the above is ignored and we always + // wait (timeout can still cause us to return) because we know that + // we won't get any more input. This matters if the input file is + // truncated and we are doing single-shot decoding, that is, + // timeout = 0 and LZMA_FINISH is used on the first call to + // lzma_code() and the output buffer is known to be big enough + // to hold all uncompressed data: + // + // - If LZMA_FINISH wasn't handled specially, we could return + // LZMA_OK before providing all output that is possible with the + // truncated input. The rest would be available if lzma_code() was + // called again but then it's not single-shot decoding anymore. + // + // - By handling LZMA_FINISH specially here, the first call will + // produce all the output, matching the behavior of the + // single-threaded decoder. + // + // So it's a very specific corner case but also easy to avoid. Note + // that this special handling of LZMA_FINISH has no effect for + // single-shot decoding when the input file is valid (not truncated); + // premature LZMA_OK wouldn't be possible as long as timeout = 0. + const bool waiting_allowed = action == LZMA_FINISH + || (*in_pos == in_size && !coder->out_was_filled); coder->out_was_filled = false; while (true) |