Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Lib/test/test_bz2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,29 @@ def test_uninitialized_BZ2Decompressor_crash(self):
self.assertEqual(BZ2Decompressor.__new__(BZ2Decompressor).
decompress(bytes()), b'')

@support.nomemtest
def test_decompress_memoryerror_no_dangling_input(self):
# gh-148395 / CVE-2026-6100: after MemoryError in decompress(), the
# decompressor must not keep a dangling pointer into the input buffer.
import _testcapi
data = bz2.compress(b'x' * 4096)
for start in range(0, 40):
d = bz2.BZ2Decompressor()
try:
_testcapi.set_nomemory(start, start + 1)
try:
d.decompress(bytearray(data), max_length=0)
except MemoryError:
pass
finally:
_testcapi.remove_mem_hooks()
try:
out = d.decompress(bytearray(data))
except (MemoryError, ValueError, EOFError, OSError):
continue
Comment on lines +1081 to +1082

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Make the bz2 test detect the missing pointer reset

When the injected failure reaches the tail-buffer allocation (start == 2 on a --with-pydebug build), removing both bzs->next_in = NULL assignments from _bz2module.c makes the follow-up call raise OSError: Invalid data stream; this handler accepts that result, so the test still passes with the CVE fix reverted. Use a follow-up operation and explicit expected outcome that distinguish a cleared pointer from the dangling-pointer state rather than treating this decompression error as success.

Useful? React with 👍 / 👎.

self.assertIsInstance(out, bytes)
self.assertNotIn(b'\x00' * 64, out)


class CompressDecompressTest(BaseTest):
def testCompress(self):
Expand Down
23 changes: 23 additions & 0 deletions Lib/test/test_lzma.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,29 @@ def test_uninitialized_LZMADecompressor_crash(self):
self.assertEqual(LZMADecompressor.__new__(LZMADecompressor).
decompress(bytes()), b'')

@support.nomemtest
def test_decompress_memoryerror_no_dangling_input(self):
# gh-148395 / CVE-2026-6100: after MemoryError in decompress(), the
# decompressor must not keep a dangling pointer into the input buffer.
import _testcapi
data = lzma.compress(b'x' * 4096)
for start in range(0, 40):
d = lzma.LZMADecompressor()
try:
_testcapi.set_nomemory(start, start + 1)
try:
d.decompress(bytearray(data), max_length=0)
except MemoryError:
pass
finally:
_testcapi.remove_mem_hooks()
try:
out = d.decompress(bytearray(data))
except (MemoryError, ValueError, EOFError, OSError, LZMAError):
continue
self.assertIsInstance(out, bytes)
self.assertNotIn(b'\x00' * 64, out)

def test_riscv_filter_constant_exists(self):
self.assertTrue(lzma.FILTER_RISCV)

Expand Down
25 changes: 25 additions & 0 deletions Lib/test/test_zlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,31 @@ def test_refleaks_in___init__(self):
zlibd.__init__()
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)

@support.nomemtest
@unittest.skipUnless(hasattr(zlib, '_ZlibDecompressor'),
'requires zlib._ZlibDecompressor')
def test_decompress_memoryerror_no_dangling_input(self):
# gh-148395 / CVE-2026-6100: after MemoryError in decompress(), the
# decompressor must not keep a dangling pointer into the input buffer.
import _testcapi
data = zlib.compress(b'x' * 4096)
for start in range(0, 40):
d = zlib._ZlibDecompressor()
try:
_testcapi.set_nomemory(start, start + 1)
try:
d.decompress(bytearray(data), max_length=0)
except MemoryError:
pass
finally:
_testcapi.remove_mem_hooks()
try:
out = d.decompress(bytearray(data))
except (MemoryError, ValueError, EOFError, OSError, zlib.error):
continue
Comment on lines +1239 to +1240

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Make the zlib test detect the missing pointer reset

When the injected failure reaches the tail-buffer allocation (start == 2 on a --with-pydebug build), removing both self->zst.next_in = NULL assignments from zlibmodule.c makes the follow-up call raise zlib.error for an incorrect data check; this handler accepts that result, so the test still passes with the CVE fix reverted. Exercise a post-error operation with an explicit safe result that differs when the stale pointer remains instead of allowing this error to satisfy the regression test.

Useful? React with 👍 / 👎.

self.assertIsInstance(out, bytes)
self.assertNotIn(b'\x00' * 64, out)


class CustomInt:
def __index__(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Add regression tests for the CVE-2026-6100 decompressor fix so a
``bz2.BZ2Decompressor``, ``lzma.LZMADecompressor``, or
``zlib._ZlibDecompressor`` that raised ``MemoryError`` during
``decompress()`` cannot silently regain a dangling input pointer on
the next call.
Loading