From ec3731cd44c39b9162c8984c1ee663778320666d Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Fri, 11 Sep 2026 16:49:53 +0100 Subject: [PATCH] Fix an OOB read in the `hz` incremental decoder on a trailing `~` --- Lib/test/test_multibytecodec.py | 9 +++++++++ .../2026-09-11-16-50-11.gh-issue-157325.hzTild.rst | 2 ++ Modules/cjkcodecs/_codecs_cn.c | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-09-11-16-50-11.gh-issue-157325.hzTild.rst diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py index 6b032fc8604eefd..0cd822fef874003 100644 --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -265,6 +265,15 @@ def test_iso2022(self): self.assertRaises(UnicodeDecodeError, decoder.decode, b'', True) self.assertEqual(decoder.decode(b'B@$'), '\u4e16') + def test_hz_keep_buffer(self): + # A trailing '~' shouldn't read past the end of the input. + decoder = codecs.getincrementaldecoder('hz')() + self.assertEqual(decoder.decode(b'~'), '') + self.assertRaises(UnicodeDecodeError, decoder.decode, b'', True) + self.assertEqual(decoder.decode(b'~'), '~') + self.assertEqual(decoder.decode(b'~'), '') + self.assertEqual(decoder.decode(b'\n', True), '') + def test_decode_unicode(self): # Trying to decode a unicode string should raise a TypeError for enc in ALL_CJKENCODINGS: diff --git a/Misc/NEWS.d/next/Library/2026-09-11-16-50-11.gh-issue-157325.hzTild.rst b/Misc/NEWS.d/next/Library/2026-09-11-16-50-11.gh-issue-157325.hzTild.rst new file mode 100644 index 000000000000000..a5adf101c9dad3c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-11-16-50-11.gh-issue-157325.hzTild.rst @@ -0,0 +1,2 @@ +Fix an out-of-bounds read in the ``hz`` incremental decoder when the input +ends with ``~``. diff --git a/Modules/cjkcodecs/_codecs_cn.c b/Modules/cjkcodecs/_codecs_cn.c index e2c7908c9bb2753..dc89f1d899e36be 100644 --- a/Modules/cjkcodecs/_codecs_cn.c +++ b/Modules/cjkcodecs/_codecs_cn.c @@ -414,9 +414,9 @@ DECODER(hz) Py_UCS4 decoded; if (c == '~') { + REQUIRE_INBUF(2); unsigned char c2 = INBYTE2; - REQUIRE_INBUF(2); if (c2 == '~' && state->c[CN_STATE_OFFSET] == 0) OUTCHAR('~'); else if (c2 == '{' && state->c[CN_STATE_OFFSET] == 0)