Skip to content

Commit 905aab6

Browse files
gh-159739: Bound encoding-name lookahead in surrogatepass (#159785)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
1 parent 07df106 commit 905aab6

3 files changed

Lines changed: 18 additions & 2 deletions

File tree

‎Lib/test/test_codeccallbacks.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,18 @@ def test_badandgoodsurrogatepassexceptions(self):
755755
(s[:1], 1 + n)
756756
)
757757

758+
def test_surrogatepass_truncated_encoding_name(self):
759+
handler = codecs.lookup_error('surrogatepass')
760+
for width in (16, 32):
761+
encoding = f'utf-{width}-'
762+
data = (0xd800).to_bytes(width // 8, 'little')
763+
for exc in (UnicodeEncodeError(encoding, '\ud800', 0, 1, 'test'),
764+
UnicodeDecodeError(encoding, data, 0, len(data), 'test')):
765+
with self.subTest(encoding=encoding, error=type(exc).__name__):
766+
with self.assertRaises(type(exc)) as cm:
767+
handler(exc)
768+
self.assertIs(cm.exception, exc)
769+
758770
def test_badhandlerresults(self):
759771
results = ( 42, "foo", (1,2,3), ("foo", 1, 3), ("foo", None), ("foo",), ("foo", 1, 3), ("foo", None), ("foo",) )
760772
encs = ("ascii", "latin-1", "iso-8859-1", "iso-8859-15")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid reading past the end of an encoding name when the ``surrogatepass``
2+
error handler receives a truncated UTF-16 or UTF-32 name.

‎Python/codecs.c‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,8 @@ get_standard_encoding_impl(const char *encoding, int *bytelength)
11731173
}
11741174
if (*encoding == '-' || *encoding == '_' )
11751175
encoding++;
1176-
if (Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
1176+
if (encoding[0] != '\0' &&
1177+
Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
11771178
if (Py_TOLOWER(encoding[0]) == 'b')
11781179
return ENC_UTF16BE;
11791180
if (Py_TOLOWER(encoding[0]) == 'l')
@@ -1192,7 +1193,8 @@ get_standard_encoding_impl(const char *encoding, int *bytelength)
11921193
}
11931194
if (*encoding == '-' || *encoding == '_' )
11941195
encoding++;
1195-
if (Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
1196+
if (encoding[0] != '\0' &&
1197+
Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
11961198
if (Py_TOLOWER(encoding[0]) == 'b')
11971199
return ENC_UTF32BE;
11981200
if (Py_TOLOWER(encoding[0]) == 'l')

0 commit comments

Comments
 (0)