Commit 65198524 for xz

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

    Tests: Make some memory allocations fail in fuzzers

diff --git a/tests/ossfuzz/fuzz_common.h b/tests/ossfuzz/fuzz_common.h
index 489beacb..574fd98e 100644
--- a/tests/ossfuzz/fuzz_common.h
+++ b/tests/ossfuzz/fuzz_common.h
@@ -13,6 +13,7 @@
 #include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdatomic.h>
 #include "lzma.h"

 // Some header values can make liblzma allocate a lot of RAM
@@ -24,6 +25,42 @@
 #define IN_CHUNK_SIZE 2047


+static atomic_ulong alloc_fail;
+
+
+static void *
+my_alloc(void *opaque, size_t nmemb, size_t size)
+{
+	(void)opaque;
+	(void)nmemb;
+
+	if (--alloc_fail == 0)
+		return NULL;
+
+	return malloc(size);
+}
+
+
+static void
+prepare_stream(lzma_stream *stream, const uint8_t *inbuf, size_t inbuf_size)
+{
+	stream->next_in = inbuf;
+	stream->avail_in = inbuf_size;
+
+	// Unless the input is very tiny, make one allocation in 1024 fail
+	// based on the last two input bytes and inbuf_size.
+	if (inbuf_size >= 10) {
+		alloc_fail = inbuf[inbuf_size - 2]
+				^ ((inbuf[inbuf_size - 1]) << 2)
+				^ (inbuf_size & 0x3FF);
+
+		static const lzma_allocator my_allocator
+				= { &my_alloc, NULL, NULL };
+		stream->allocator = &my_allocator;
+	}
+}
+
+
 static void
 fuzz_code(lzma_stream *stream, const uint8_t *inbuf, size_t inbuf_size)
 {
diff --git a/tests/ossfuzz/fuzz_decode_alone.c b/tests/ossfuzz/fuzz_decode_alone.c
index 79f3c64f..6b774841 100644
--- a/tests/ossfuzz/fuzz_decode_alone.c
+++ b/tests/ossfuzz/fuzz_decode_alone.c
@@ -21,14 +21,16 @@ extern int
 LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
 {
 	lzma_stream strm = LZMA_STREAM_INIT;
-	strm.next_in = inbuf;
-	strm.avail_in = inbuf_size;
+	prepare_stream(&strm, inbuf, inbuf_size);

 	lzma_ret ret;

 	for (int i = 0; i < 3; ++i) {
 		ret = lzma_alone_decoder(&strm, MEM_LIMIT);

+		if (ret == LZMA_MEM_ERROR)
+			continue;
+
 		if (ret != LZMA_OK) {
 			// This should never happen unless the system has
 			// no free memory or address space to allow the small
diff --git a/tests/ossfuzz/fuzz_decode_stream.c b/tests/ossfuzz/fuzz_decode_stream.c
index 550c4118..054570ee 100644
--- a/tests/ossfuzz/fuzz_decode_stream.c
+++ b/tests/ossfuzz/fuzz_decode_stream.c
@@ -21,8 +21,7 @@ extern int
 LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
 {
 	lzma_stream strm = LZMA_STREAM_INIT;
-	strm.next_in = inbuf;
-	strm.avail_in = inbuf_size;
+	prepare_stream(&strm, inbuf, inbuf_size);

 	lzma_ret ret;

@@ -47,6 +46,9 @@ LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
 		ret = lzma_stream_decoder(&strm, MEM_LIMIT, LZMA_IGNORE_CHECK
 				| (i >= 2 ? LZMA_CONCATENATED : 0));

+		if (ret == LZMA_MEM_ERROR)
+			continue;
+
 		if (ret != LZMA_OK) {
 			// This should never happen unless the system has
 			// no free memory or address space to allow the small
diff --git a/tests/ossfuzz/fuzz_decode_stream_mt.c b/tests/ossfuzz/fuzz_decode_stream_mt.c
index 6beb68c5..d633e04d 100644
--- a/tests/ossfuzz/fuzz_decode_stream_mt.c
+++ b/tests/ossfuzz/fuzz_decode_stream_mt.c
@@ -20,8 +20,7 @@ extern int
 LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
 {
 	lzma_stream strm = LZMA_STREAM_INIT;
-	strm.next_in = inbuf;
-	strm.avail_in = inbuf_size;
+	prepare_stream(&strm, inbuf, inbuf_size);

 	lzma_mt mt = {
 		.flags = /*LZMA_CONCATENATED |*/ LZMA_IGNORE_CHECK,
@@ -39,6 +38,9 @@ LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)

 		ret = lzma_stream_decoder_mt(&strm, &mt);

+		if (ret == LZMA_MEM_ERROR)
+			continue;
+
 		if (ret != LZMA_OK) {
 			// This should never happen unless the system has
 			// no free memory or address space to allow the small
diff --git a/tests/ossfuzz/fuzz_encode_stream.c b/tests/ossfuzz/fuzz_encode_stream.c
index 9438263f..b10a9bea 100644
--- a/tests/ossfuzz/fuzz_encode_stream.c
+++ b/tests/ossfuzz/fuzz_encode_stream.c
@@ -69,11 +69,15 @@ LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)

 	// initialize empty LZMA stream
 	lzma_stream strm = LZMA_STREAM_INIT;
+	prepare_stream(&strm, inbuf, inbuf_size);

 	// Initialize the stream encoder using the above
 	// stream, filter chain and CRC64.
 	lzma_ret ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC64);
 	if (ret != LZMA_OK) {
+		if (ret == LZMA_MEM_ERROR)
+			return 0;
+
 		fprintf(stderr, "lzma_stream_encoder() failed (%d)\n", ret);
 		abort();
 	}