Skip to content
Open
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
18 changes: 18 additions & 0 deletions Lib/test/test_multibytecodec.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,24 @@ def test_setstate_validates_input(self):
self.assertRaises(TypeError, decoder.setstate, (b"1234", "invalid"))
self.assertRaises(UnicodeDecodeError, decoder.setstate, (b"123456789", 0))

def test_setstate_invalid_designation(self):
# gh-153603: an unknown charset designation in the state must not crash
# the decoder. 0xff is not a registered charset mark and 0x21 ('!') is
# a GL byte that triggers the designation lookup.
for name in ('iso-2022-jp', 'iso-2022-kr'):
with self.subTest(codec=name):
decoder = codecs.getincrementaldecoder(name)()
decoder.setstate((b'', 0xff))
with self.assertRaises(UnicodeDecodeError) as cm:
decoder.decode(b'!', final=True)
self.assertEqual(cm.exception.reason,
'illegal multibyte sequence')
self.assertEqual((cm.exception.start, cm.exception.end), (0, 1))
# One illegal byte is reported, so error handlers still work.
decoder = codecs.getincrementaldecoder(name)(errors='replace')
decoder.setstate((b'', 0xff))
self.assertEqual(decoder.decode(b'!', final=True), '\ufffd')

class Test_StreamReader(unittest.TestCase):
def test_bug1728403(self):
try:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix a crash in the ISO-2022 decoders when decoding a byte after an unknown
charset designation is set via the decoder's ``setstate`` method.
Patch by tonghuaroot.
13 changes: 7 additions & 6 deletions Modules/cjkcodecs/_codecs_iso2022.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,16 @@ DECODER(iso2022)
dsg = dsgcache;
else {
for (dsg = CONFIG_DESIGNATIONS;
dsg->mark != charset
#ifdef Py_DEBUG
&& dsg->mark != '\0'
#endif
; dsg++)
dsg->mark != charset && dsg->mark != '\0';
dsg++)
{
/* noop */
}
assert(dsg->mark != '\0');
if (dsg->mark == '\0') {
/* Unknown charset designation from a corrupt
setstate(); no width to trust, report one byte. */
return 1;
}
dsgcache = dsg;
}

Expand Down
Loading