Commit ff834f25 for xz

commit ff834f25ae4f9b3e6270d41b4c843b8b1183346c
Author: Lasse Collin <lasse.collin@tukaani.org>
Date:   Wed Sep 9 14:14:40 2026 +0300

    Tests: Test lzma_alone_decoder() reuse after dictionary allocation failure

    This test crashes if both of the two previous commits are reverted.

diff --git a/tests/Makefile.am b/tests/Makefile.am
index d5e63e7f..53fe347e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -49,6 +49,7 @@ check_PROGRAMS = \
 	test_index_hash \
 	test_bcj_exact_size \
 	test_memlimit \
+	test_alone_decoder \
 	test_lzip_decoder \
 	test_vli

@@ -65,6 +66,7 @@ TESTS = \
 	test_index_hash \
 	test_bcj_exact_size \
 	test_memlimit \
+	test_alone_decoder \
 	test_lzip_decoder \
 	test_vli \
 	test_files.sh \
diff --git a/tests/test_alone_decoder.c b/tests/test_alone_decoder.c
new file mode 100644
index 00000000..63c32713
--- /dev/null
+++ b/tests/test_alone_decoder.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       test_alone_decoder.c
+/// \brief      Test lzma_alone_decoder()
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+
+#define MEMLIMIT (16U << 20)
+#define TOO_BIG_ALLOC (1U << 20)
+
+
+#ifdef HAVE_DECODERS
+static void *
+my_alloc(void *opaque, size_t nmemb, size_t size)
+{
+	(void)opaque;
+	(void)nmemb;
+
+	if (size >= TOO_BIG_ALLOC)
+		return NULL;
+
+	return malloc(size);
+}
+
+
+static lzma_allocator my_allocator = { &my_alloc, NULL, NULL };
+
+
+static void
+test_reuse_after_failure(void)
+{
+	// 4 KiB dictionary
+	size_t small_dict_size;
+	uint8_t *small_dict = tuktest_file_from_srcdir(
+			"files/good-unknown_size-with_eopm.lzma",
+			&small_dict_size);
+
+	// 8 MiB dictionary
+	size_t big_dict_size;
+	uint8_t *big_dict = tuktest_file_from_srcdir(
+			"files/good-unknown_size-with_eopm.lzma",
+			&big_dict_size);
+	big_dict[2] = 0x00;
+	big_dict[3] = 0x80;
+
+	uint8_t out[256];
+
+	lzma_stream strm = LZMA_STREAM_INIT;
+	strm.allocator = &my_allocator;
+
+	assert_lzma_ret(lzma_alone_decoder(&strm, MEMLIMIT), LZMA_OK);
+	strm.next_in = small_dict;
+	strm.avail_in = small_dict_size;
+	strm.next_out = out;
+	strm.avail_out = sizeof(out);
+	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+
+	assert_lzma_ret(lzma_alone_decoder(&strm, MEMLIMIT), LZMA_OK);
+	strm.next_in = big_dict;
+	strm.avail_in = big_dict_size;
+	strm.next_out = out;
+	strm.avail_out = sizeof(out);
+	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEM_ERROR);
+
+	assert_lzma_ret(lzma_alone_decoder(&strm, MEMLIMIT), LZMA_OK);
+	strm.next_in = small_dict;
+	strm.avail_in = small_dict_size;
+	strm.next_out = out;
+	strm.avail_out = sizeof(out);
+	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+
+	lzma_end(&strm);
+}
+#endif
+
+
+extern int
+main(int argc, char **argv)
+{
+	tuktest_start(argc, argv);
+
+#ifndef HAVE_DECODERS
+	tuktest_early_skip("Decoder support is disabled");
+#else
+	tuktest_run(test_reuse_after_failure);
+#endif
+
+	return tuktest_end();
+}
diff --git a/tests/tests.cmake b/tests/tests.cmake
index d67fbc39..715b0c1e 100644
--- a/tests/tests.cmake
+++ b/tests/tests.cmake
@@ -51,6 +51,7 @@ if(BUILD_TESTING)
     #################

     set(LIBLZMA_TESTS
+        test_alone_decoder
         test_bcj_exact_size
         test_block_header
         test_check