mirror of https://git.tukaani.org/xz.git
xz: Fix a crash in progress indicator when in passthru mode.
"xz -dcfv not_an_xz_file" crashed (all four options are required to trigger it). It caused xz to call lzma_get_progress(&strm, ...) when no coder was initialized in strm. In this situation strm.internal is NULL which leads to a crash in lzma_get_progress(). The bug was introduced when xz started using lzma_get_progress() to get progress info for multi-threaded compression, so the bug is present in versions 5.1.3alpha and higher. Thanks to Filip Palian <Filip.Palian@pjwstk.edu.pl> for the bug report.
This commit is contained in:
parent
fcc419e3c3
commit
3ca432d9cc
|
@ -902,16 +902,19 @@ coder_run(const char *filename)
|
||||||
mytime_set_start_time();
|
mytime_set_start_time();
|
||||||
|
|
||||||
// Initialize the progress indicator.
|
// Initialize the progress indicator.
|
||||||
|
const bool is_passthru = init_ret
|
||||||
|
== CODER_INIT_PASSTHRU;
|
||||||
const uint64_t in_size
|
const uint64_t in_size
|
||||||
= pair->src_st.st_size <= 0
|
= pair->src_st.st_size <= 0
|
||||||
? 0 : pair->src_st.st_size;
|
? 0 : pair->src_st.st_size;
|
||||||
message_progress_start(&strm, in_size);
|
message_progress_start(&strm,
|
||||||
|
is_passthru, in_size);
|
||||||
|
|
||||||
// Do the actual coding or passthru.
|
// Do the actual coding or passthru.
|
||||||
if (init_ret == CODER_INIT_NORMAL)
|
if (is_passthru)
|
||||||
success = coder_normal(pair);
|
|
||||||
else
|
|
||||||
success = coder_passthru(pair);
|
success = coder_passthru(pair);
|
||||||
|
else
|
||||||
|
success = coder_normal(pair);
|
||||||
|
|
||||||
message_progress_end(success);
|
message_progress_end(success);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,11 @@ static bool progress_active = false;
|
||||||
/// Pointer to lzma_stream used to do the encoding or decoding.
|
/// Pointer to lzma_stream used to do the encoding or decoding.
|
||||||
static lzma_stream *progress_strm;
|
static lzma_stream *progress_strm;
|
||||||
|
|
||||||
|
/// This is true if we are in passthru mode (not actually compressing or
|
||||||
|
/// decompressing) and thus cannot use lzma_get_progress(progress_strm, ...).
|
||||||
|
/// That is, we are using coder_passthru() in coder.c.
|
||||||
|
static bool progress_is_from_passthru;
|
||||||
|
|
||||||
/// Expected size of the input stream is needed to show completion percentage
|
/// Expected size of the input stream is needed to show completion percentage
|
||||||
/// and estimate remaining time.
|
/// and estimate remaining time.
|
||||||
static uint64_t expected_in_size;
|
static uint64_t expected_in_size;
|
||||||
|
@ -241,11 +246,12 @@ message_filename(const char *src_name)
|
||||||
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
message_progress_start(lzma_stream *strm, uint64_t in_size)
|
message_progress_start(lzma_stream *strm, bool is_passthru, uint64_t in_size)
|
||||||
{
|
{
|
||||||
// Store the pointer to the lzma_stream used to do the coding.
|
// Store the pointer to the lzma_stream used to do the coding.
|
||||||
// It is needed to find out the position in the stream.
|
// It is needed to find out the position in the stream.
|
||||||
progress_strm = strm;
|
progress_strm = strm;
|
||||||
|
progress_is_from_passthru = is_passthru;
|
||||||
|
|
||||||
// Store the expected size of the file. If we aren't printing any
|
// Store the expected size of the file. If we aren't printing any
|
||||||
// statistics, then is will be unused. But since it is possible
|
// statistics, then is will be unused. But since it is possible
|
||||||
|
@ -507,7 +513,15 @@ progress_pos(uint64_t *in_pos,
|
||||||
uint64_t *compressed_pos, uint64_t *uncompressed_pos)
|
uint64_t *compressed_pos, uint64_t *uncompressed_pos)
|
||||||
{
|
{
|
||||||
uint64_t out_pos;
|
uint64_t out_pos;
|
||||||
lzma_get_progress(progress_strm, in_pos, &out_pos);
|
if (progress_is_from_passthru) {
|
||||||
|
// In passthru mode the progress info is in total_in/out but
|
||||||
|
// the *progress_strm itself isn't initialized and thus we
|
||||||
|
// cannot use lzma_get_progress().
|
||||||
|
*in_pos = progress_strm->total_in;
|
||||||
|
out_pos = progress_strm->total_out;
|
||||||
|
} else {
|
||||||
|
lzma_get_progress(progress_strm, in_pos, &out_pos);
|
||||||
|
}
|
||||||
|
|
||||||
// It cannot have processed more input than it has been given.
|
// It cannot have processed more input than it has been given.
|
||||||
assert(*in_pos <= progress_strm->total_in);
|
assert(*in_pos <= progress_strm->total_in);
|
||||||
|
|
|
@ -150,7 +150,8 @@ extern void message_filename(const char *src_name);
|
||||||
/// \param strm Pointer to lzma_stream used for the coding.
|
/// \param strm Pointer to lzma_stream used for the coding.
|
||||||
/// \param in_size Size of the input file, or zero if unknown.
|
/// \param in_size Size of the input file, or zero if unknown.
|
||||||
///
|
///
|
||||||
extern void message_progress_start(lzma_stream *strm, uint64_t in_size);
|
extern void message_progress_start(lzma_stream *strm,
|
||||||
|
bool is_passthru, uint64_t in_size);
|
||||||
|
|
||||||
|
|
||||||
/// Update the progress info if in verbose mode and enough time has passed
|
/// Update the progress info if in verbose mode and enough time has passed
|
||||||
|
|
Loading…
Reference in New Issue