From d43200c303cd5f19bb61c2bf710f0711365a95dc Mon Sep 17 00:00:00 2001 From: bunnysayzz Date: Thu, 22 Oct 2026 05:26:01 +0000 Subject: [PATCH] gh-160000: Fix LZMADecompressor raising on repeated empty decompress calls --- Lib/test/test_lzma.py | 14 ++++++++++++++ .../2026-10-22-10-55-00.gh-issue-160000.a1b2c3.rst | 2 ++ Modules/_lzmamodule.c | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-22-10-55-00.gh-issue-160000.a1b2c3.rst diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py index df0b66039d77a1a..9faca98e3d2db90 100644 --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -78,6 +78,20 @@ def test_decompressor_after_eof(self): lzd.decompress(COMPRESSED_XZ) self.assertRaises(EOFError, lzd.decompress, b"nyan") + def test_decompressor_empty_max_length_zero_repeated(self): + # gh-160000: repeated decompress(b'', max_length=0) calls must + # return b'' instead of raising LZMAError on the second call. + lzd = LZMADecompressor() + for _ in range(3): + self.assertEqual(lzd.decompress(b'', max_length=0), b'') + # Same after real input: one byte out, then empty calls, + # then the rest of the stream still decompresses. + lzd = LZMADecompressor() + self.assertEqual(lzd.decompress(COMPRESSED_XZ, 1), INPUT[:1]) + for _ in range(3): + self.assertEqual(lzd.decompress(b'', max_length=0), b'') + self.assertEqual(lzd.decompress(b''), INPUT[1:]) + def test_decompressor_memlimit(self): lzd = LZMADecompressor(memlimit=1024) self.assertRaises(LZMAError, lzd.decompress, COMPRESSED_XZ) diff --git a/Misc/NEWS.d/next/Library/2026-10-22-10-55-00.gh-issue-160000.a1b2c3.rst b/Misc/NEWS.d/next/Library/2026-10-22-10-55-00.gh-issue-160000.a1b2c3.rst new file mode 100644 index 000000000000000..a0d5ed7a5a9cda7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-22-10-55-00.gh-issue-160000.a1b2c3.rst @@ -0,0 +1,2 @@ +Fix :class:`lzma.LZMADecompressor` raising :exc:`LZMAError` on repeated +``decompress(b'', max_length=0)`` calls. diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index 92784904f3c9930..a7f2c726028b73d 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -959,7 +959,8 @@ decompress_buf(Decompressor *d, Py_ssize_t max_length) lzret = lzma_code(lzs, LZMA_RUN); Py_END_ALLOW_THREADS - if (lzret == LZMA_BUF_ERROR && lzs->avail_in == 0 && lzs->avail_out > 0) { + if (lzret == LZMA_BUF_ERROR && + (lzs->avail_in == 0 || lzs->avail_out == 0)) { lzret = LZMA_OK; /* That wasn't a real error */ } if (catch_lzma_error(state, lzret)) {