Merge branch 'jn/5.0.0' into maint

Two important recent fixes.

* jn/5.0.0:
  Docs: Fix a bug in xz_pipe_decomp.c example program.
  liblzma: Fix possibility of incorrect LZMA_BUF_ERROR.
diff --git a/debian/changelog b/debian/changelog
index 2dccf6a..fa05402 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -13,9 +13,14 @@
         - lzma_stream_buffer_encode() and lzma_block_buffer_encode()
           reject unsupported integrity checks;
         - lzma_block_encoder() checks for block == NULL.
+      - bcj: Fix possibility of incorrect LZMA_BUF_ERROR (reported in
+        XZ Embedded as Fedora bug 735408).
       - Plugs a memory leak in lzma_stream_encoder().
       - lzma_index_init() returns NULL instead of segfaulting on
         allocation failure.
+    * docs/examples/xz_pipe_decompress.c checks that the last
+      lzma_code() call returned LZMA_STREAM_END, since otherwise the
+      compressed file ended without a proper footer.
     * "xz -v -v --list" does not free() filter options unless the
       filter options array has been initialized.  This prevents
       reading and free()ing pointers from past the end of an on-stack
diff --git a/debian/patches/bcj-flush-to-empty-buffer b/debian/patches/bcj-flush-to-empty-buffer
new file mode 100644
index 0000000..b3b25c4
--- /dev/null
+++ b/debian/patches/bcj-flush-to-empty-buffer
@@ -0,0 +1,190 @@
+From: Lasse Collin <lasse.collin@tukaani.org>
+Date: Mon, 28 May 2012 20:42:11 +0300
+Subject: liblzma: Fix possibility of incorrect LZMA_BUF_ERROR.
+
+lzma_code() could incorrectly return LZMA_BUF_ERROR if
+all of the following was true:
+
+  - The caller knows how many bytes of output to expect
+    and only provides that much output space.
+
+  - When the last output bytes are decoded, the
+    caller-provided input buffer ends right before
+    the LZMA2 end of payload marker. So LZMA2 won't
+    provide more output anymore, but it won't know it
+    yet and thus won't return LZMA_STREAM_END yet.
+
+  - A BCJ filter is in use and it hasn't left any
+    unfiltered bytes in the temp buffer. This can happen
+    with any BCJ filter, but in practice it's more likely
+    with filters other than the x86 BCJ.
+
+Another situation where the bug can be triggered happens
+if the uncompressed size is zero bytes and no output space
+is provided. In this case the decompression can fail even
+if the whole input file is given to lzma_code().
+
+A similar bug was fixed in XZ Embedded on 2011-09-19.
+---
+ src/liblzma/simple/simple_coder.c |   2 +-
+ tests/Makefile.am                 |   4 +-
+ tests/test_bcj_exact_size.c       | 112 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 116 insertions(+), 2 deletions(-)
+ create mode 100644 tests/test_bcj_exact_size.c
+
+diff --git a/src/liblzma/simple/simple_coder.c b/src/liblzma/simple/simple_coder.c
+index 06db86ec..47183fe1 100644
+--- a/src/liblzma/simple/simple_coder.c
++++ b/src/liblzma/simple/simple_coder.c
+@@ -110,7 +110,7 @@ simple_code(lzma_coder *coder, lzma_allocator *allocator,
+ 	// filtered if the buffer sizes used by the application are reasonable.
+ 	const size_t out_avail = out_size - *out_pos;
+ 	const size_t buf_avail = coder->size - coder->pos;
+-	if (out_avail > buf_avail) {
++	if (out_avail > buf_avail || buf_avail == 0) {
+ 		// Store the old position so that we know from which byte
+ 		// to start filtering.
+ 		const size_t out_start = *out_pos;
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 0469264a..6d3e4481 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -34,7 +34,8 @@ check_PROGRAMS = \
+ 	test_stream_flags \
+ 	test_filter_flags \
+ 	test_block_header \
+-	test_index
++	test_index \
++	test_bcj_exact_size
+ 
+ TESTS = \
+ 	test_check \
+@@ -42,6 +43,7 @@ TESTS = \
+ 	test_filter_flags \
+ 	test_block_header \
+ 	test_index \
++	test_bcj_exact_size \
+ 	test_files.sh \
+ 	test_compress.sh \
+ 	test_scripts.sh
+diff --git a/tests/test_bcj_exact_size.c b/tests/test_bcj_exact_size.c
+new file mode 100644
+index 00000000..cbd93405
+--- /dev/null
++++ b/tests/test_bcj_exact_size.c
+@@ -0,0 +1,112 @@
++///////////////////////////////////////////////////////////////////////////////
++//
++/// \file       test_bcj_exact_size.c
++/// \brief      Tests BCJ decoding when the output size is known
++///
++/// These tests fail with XZ Utils 5.0.3 and earlier.
++//
++//  Author:     Lasse Collin
++//
++//  This file has been put into the public domain.
++//  You can do whatever you want with this file.
++//
++///////////////////////////////////////////////////////////////////////////////
++
++#include "tests.h"
++
++
++/// Something to be compressed
++static const uint8_t in[16] = "0123456789ABCDEF";
++
++/// in[] after compression
++static uint8_t compressed[1024];
++static size_t compressed_size = 0;
++
++/// Output buffer for decompressing compressed[]
++static uint8_t out[sizeof(in)];
++
++
++static void
++compress(void)
++{
++	// Compress with PowerPC BCJ and LZMA2. PowerPC BCJ is used because
++	// it has fixed 4-byte alignment which makes triggering the potential
++	// bug easy.
++	lzma_options_lzma opt_lzma2;
++	succeed(lzma_lzma_preset(&opt_lzma2, 0));
++
++	lzma_filter filters[3] = {
++		{ .id = LZMA_FILTER_POWERPC, .options = NULL },
++		{ .id = LZMA_FILTER_LZMA2, .options = &opt_lzma2 },
++		{ .id = LZMA_VLI_UNKNOWN, .options = NULL },
++	};
++
++	expect(lzma_stream_buffer_encode(filters, LZMA_CHECK_CRC32, NULL,
++			in, sizeof(in),
++			compressed, &compressed_size, sizeof(compressed))
++			== LZMA_OK);
++}
++
++
++static void
++decompress(void)
++{
++	lzma_stream strm = LZMA_STREAM_INIT;
++	expect(lzma_stream_decoder(&strm, 10 << 20, 0) == LZMA_OK);
++
++	strm.next_in = compressed;
++	strm.next_out = out;
++
++	while (true) {
++		if (strm.total_in < compressed_size)
++			strm.avail_in = 1;
++
++		const lzma_ret ret = lzma_code(&strm, LZMA_RUN);
++		if (ret == LZMA_STREAM_END) {
++			expect(strm.total_in == compressed_size);
++			expect(strm.total_out == sizeof(in));
++			return;
++		}
++
++		expect(ret == LZMA_OK);
++
++		if (strm.total_out < sizeof(in))
++			strm.avail_out = 1;
++	}
++}
++
++
++static void
++decompress_empty(void)
++{
++	// An empty file with one Block using PowerPC BCJ and LZMA2.
++	static const uint8_t empty_bcj_lzma2[] = {
++		0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01,
++		0x69, 0x22, 0xDE, 0x36, 0x02, 0x01, 0x05, 0x00,
++		0x21, 0x01, 0x00, 0x00, 0x7F, 0xE0, 0xF1, 0xC8,
++		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		0x00, 0x01, 0x11, 0x00, 0x3B, 0x96, 0x5F, 0x73,
++		0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
++		0x00, 0x01, 0x59, 0x5A
++	};
++
++	// Decompress without giving any output space.
++	uint64_t memlimit = 1 << 20;
++	size_t in_pos = 0;
++	size_t out_pos = 0;
++	expect(lzma_stream_buffer_decode(&memlimit, 0, NULL,
++			empty_bcj_lzma2, &in_pos, sizeof(empty_bcj_lzma2),
++			out, &out_pos, 0) == LZMA_OK);
++	expect(in_pos == sizeof(empty_bcj_lzma2));
++	expect(out_pos == 0);
++}
++
++
++extern int
++main(void)
++{
++	compress();
++	decompress();
++	decompress_empty();
++	return 0;
++}
+-- 
+1.7.11.rc3
+
diff --git a/debian/patches/series b/debian/patches/series
index fa7f036..2023d9f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -14,3 +14,4 @@
 it-stray-N
 xzdiff-save-diff-status
 xzgrep-ignore-SIGPIPE
+bcj-flush-to-empty-buffer
diff --git a/doc/examples/xz_pipe_decomp.c b/doc/examples/xz_pipe_decomp.c
index d4b204d..fb5ad89 100644
--- a/doc/examples/xz_pipe_decomp.c
+++ b/doc/examples/xz_pipe_decomp.c
@@ -1,7 +1,7 @@
 /*
  * xz_pipe_decomp.c
  * A simple example of pipe-only xz decompressor implementation.
- * version: 2010-07-12 - by Daniel Mealha Cabrita
+ * version: 2012-06-14 - by Daniel Mealha Cabrita
  * Not copyrighted -- provided to the public domain.
  *
  * Compiling:
@@ -101,6 +101,14 @@
 		} while (strm.avail_out == 0);
 	}
 
+	/* Bug fix (2012-06-14): If no errors were detected, check
+	   that the last lzma_code() call returned LZMA_STREAM_END.
+	   If not, the file is probably truncated. */
+	if ((ret == RET_OK) && (ret_xz != LZMA_STREAM_END)) {
+		fprintf (stderr, "Input truncated or corrupt\n");
+		ret = RET_ERROR_DECOMPRESSION;
+	}
+
 	lzma_end (&strm);
 	return ret;
 }
diff --git a/src/liblzma/simple/simple_coder.c b/src/liblzma/simple/simple_coder.c
index 06db86e..47183fe 100644
--- a/src/liblzma/simple/simple_coder.c
+++ b/src/liblzma/simple/simple_coder.c
@@ -110,7 +110,7 @@
 	// filtered if the buffer sizes used by the application are reasonable.
 	const size_t out_avail = out_size - *out_pos;
 	const size_t buf_avail = coder->size - coder->pos;
-	if (out_avail > buf_avail) {
+	if (out_avail > buf_avail || buf_avail == 0) {
 		// Store the old position so that we know from which byte
 		// to start filtering.
 		const size_t out_start = *out_pos;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0469264..6d3e448 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -34,7 +34,8 @@
 	test_stream_flags \
 	test_filter_flags \
 	test_block_header \
-	test_index
+	test_index \
+	test_bcj_exact_size
 
 TESTS = \
 	test_check \
@@ -42,6 +43,7 @@
 	test_filter_flags \
 	test_block_header \
 	test_index \
+	test_bcj_exact_size \
 	test_files.sh \
 	test_compress.sh \
 	test_scripts.sh
diff --git a/tests/test_bcj_exact_size.c b/tests/test_bcj_exact_size.c
new file mode 100644
index 0000000..cbd9340
--- /dev/null
+++ b/tests/test_bcj_exact_size.c
@@ -0,0 +1,112 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       test_bcj_exact_size.c
+/// \brief      Tests BCJ decoding when the output size is known
+///
+/// These tests fail with XZ Utils 5.0.3 and earlier.
+//
+//  Author:     Lasse Collin
+//
+//  This file has been put into the public domain.
+//  You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+
+/// Something to be compressed
+static const uint8_t in[16] = "0123456789ABCDEF";
+
+/// in[] after compression
+static uint8_t compressed[1024];
+static size_t compressed_size = 0;
+
+/// Output buffer for decompressing compressed[]
+static uint8_t out[sizeof(in)];
+
+
+static void
+compress(void)
+{
+	// Compress with PowerPC BCJ and LZMA2. PowerPC BCJ is used because
+	// it has fixed 4-byte alignment which makes triggering the potential
+	// bug easy.
+	lzma_options_lzma opt_lzma2;
+	succeed(lzma_lzma_preset(&opt_lzma2, 0));
+
+	lzma_filter filters[3] = {
+		{ .id = LZMA_FILTER_POWERPC, .options = NULL },
+		{ .id = LZMA_FILTER_LZMA2, .options = &opt_lzma2 },
+		{ .id = LZMA_VLI_UNKNOWN, .options = NULL },
+	};
+
+	expect(lzma_stream_buffer_encode(filters, LZMA_CHECK_CRC32, NULL,
+			in, sizeof(in),
+			compressed, &compressed_size, sizeof(compressed))
+			== LZMA_OK);
+}
+
+
+static void
+decompress(void)
+{
+	lzma_stream strm = LZMA_STREAM_INIT;
+	expect(lzma_stream_decoder(&strm, 10 << 20, 0) == LZMA_OK);
+
+	strm.next_in = compressed;
+	strm.next_out = out;
+
+	while (true) {
+		if (strm.total_in < compressed_size)
+			strm.avail_in = 1;
+
+		const lzma_ret ret = lzma_code(&strm, LZMA_RUN);
+		if (ret == LZMA_STREAM_END) {
+			expect(strm.total_in == compressed_size);
+			expect(strm.total_out == sizeof(in));
+			return;
+		}
+
+		expect(ret == LZMA_OK);
+
+		if (strm.total_out < sizeof(in))
+			strm.avail_out = 1;
+	}
+}
+
+
+static void
+decompress_empty(void)
+{
+	// An empty file with one Block using PowerPC BCJ and LZMA2.
+	static const uint8_t empty_bcj_lzma2[] = {
+		0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01,
+		0x69, 0x22, 0xDE, 0x36, 0x02, 0x01, 0x05, 0x00,
+		0x21, 0x01, 0x00, 0x00, 0x7F, 0xE0, 0xF1, 0xC8,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0x11, 0x00, 0x3B, 0x96, 0x5F, 0x73,
+		0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0x59, 0x5A
+	};
+
+	// Decompress without giving any output space.
+	uint64_t memlimit = 1 << 20;
+	size_t in_pos = 0;
+	size_t out_pos = 0;
+	expect(lzma_stream_buffer_decode(&memlimit, 0, NULL,
+			empty_bcj_lzma2, &in_pos, sizeof(empty_bcj_lzma2),
+			out, &out_pos, 0) == LZMA_OK);
+	expect(in_pos == sizeof(empty_bcj_lzma2));
+	expect(out_pos == 0);
+}
+
+
+extern int
+main(void)
+{
+	compress();
+	decompress();
+	decompress_empty();
+	return 0;
+}