aboutsummaryrefslogtreecommitdiff
path: root/linux/lib/xz
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2009-09-01 23:04:26 +0300
committerLasse Collin <lasse.collin@tukaani.org>2009-09-01 23:04:26 +0300
commit6013e9e9ea42683bdb2fe4964f68f1223000c7b1 (patch)
tree3fae9c18f7e51c5a1fcdf9a8b03721d61f530907 /linux/lib/xz
parent794c420b795216f1c11eb085f28cee31a36fd9de (diff)
downloadxz-embedded-6013e9e9ea42683bdb2fe4964f68f1223000c7b1.tar.gz
Fix infinite loop in single-call mode.
If the input file has BCJ filter and the output buffer is too small in single-call mode, the LZMA2 decoder went into an infinite loop. The actual bug was in the BCJ decoder though, which called the LZMA2 decoder twice when the output buffer was too small.
Diffstat (limited to 'linux/lib/xz')
-rw-r--r--linux/lib/xz/xz_dec_bcj.c11
-rw-r--r--linux/lib/xz/xz_dec_stream.c5
-rw-r--r--linux/lib/xz/xz_private.h2
3 files changed, 13 insertions, 5 deletions
diff --git a/linux/lib/xz/xz_dec_bcj.c b/linux/lib/xz/xz_dec_bcj.c
index f053cfd..f5b25f1 100644
--- a/linux/lib/xz/xz_dec_bcj.c
+++ b/linux/lib/xz/xz_dec_bcj.c
@@ -28,6 +28,9 @@ struct xz_dec_bcj {
*/
enum xz_ret ret;
+ /* True if we are operating in single-call mode. */
+ bool single_call;
+
/*
* Absolute position relative to the beginning of the uncompressed
* data (in a single .xz Block). We care only about the lowest 32
@@ -441,7 +444,8 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
b->out_pos += s->temp.size;
s->ret = xz_dec_lzma2_run(lzma2, b);
- if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
+ if (s->ret != XZ_STREAM_END
+ && (s->ret != XZ_OK || s->single_call))
return s->ret;
bcj_apply(s, b->out, &out_start, b->out_pos);
@@ -503,9 +507,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
return s->ret;
}
-XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(void)
+XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call)
{
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s != NULL)
+ s->single_call = single_call;
+
return s;
}
diff --git a/linux/lib/xz/xz_dec_stream.c b/linux/lib/xz/xz_dec_stream.c
index dafbe4f..76413c4 100644
--- a/linux/lib/xz/xz_dec_stream.c
+++ b/linux/lib/xz/xz_dec_stream.c
@@ -711,8 +711,10 @@ XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max)
if (s == NULL)
return NULL;
+ s->single_call = dict_max == 0;
+
#ifdef XZ_DEC_BCJ
- s->bcj = xz_dec_bcj_create();
+ s->bcj = xz_dec_bcj_create(s->single_call);
if (s->bcj == NULL)
goto error_bcj;
#endif
@@ -721,7 +723,6 @@ XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max)
if (s->lzma2 == NULL)
goto error_lzma2;
- s->single_call = dict_max == 0;
xz_dec_reset(s);
return s;
diff --git a/linux/lib/xz/xz_private.h b/linux/lib/xz/xz_private.h
index f5f4bf4..d0a7290 100644
--- a/linux/lib/xz/xz_private.h
+++ b/linux/lib/xz/xz_private.h
@@ -93,7 +93,7 @@ XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
* Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
* calling xz_dec_bcj_run().
*/
-XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(void);
+XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call);
/*
* Decode the Filter ID of a BCJ filter. This implementation doesn't