https://github.com/python/cpython/commit/905aab60f72ec5aa9183ec0b74b5eda8f9ca188d
commit: 905aab60f72ec5aa9183ec0b74b5eda8f9ca188d
branch: main
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-10-20T10:23:14-07:00
summary:

gh-159739: Bound encoding-name lookahead in surrogatepass (#159785)



Co-authored-by: Jelle Zijlstra <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.243aa8.rst
M Lib/test/test_codeccallbacks.py
M Python/codecs.c

diff --git a/Lib/test/test_codeccallbacks.py b/Lib/test/test_codeccallbacks.py
index 65d54d1004d647..7ab8eea0142520 100644
--- a/Lib/test/test_codeccallbacks.py
+++ b/Lib/test/test_codeccallbacks.py
@@ -755,6 +755,18 @@ def test_badandgoodsurrogatepassexceptions(self):
                     (s[:1], 1 + n)
                 )
 
+    def test_surrogatepass_truncated_encoding_name(self):
+        handler = codecs.lookup_error('surrogatepass')
+        for width in (16, 32):
+            encoding = f'utf-{width}-'
+            data = (0xd800).to_bytes(width // 8, 'little')
+            for exc in (UnicodeEncodeError(encoding, '\ud800', 0, 1, 'test'),
+                        UnicodeDecodeError(encoding, data, 0, len(data), 
'test')):
+                with self.subTest(encoding=encoding, error=type(exc).__name__):
+                    with self.assertRaises(type(exc)) as cm:
+                        handler(exc)
+                    self.assertIs(cm.exception, exc)
+
     def test_badhandlerresults(self):
         results = ( 42, "foo", (1,2,3), ("foo", 1, 3), ("foo", None), 
("foo",), ("foo", 1, 3), ("foo", None), ("foo",) )
         encs = ("ascii", "latin-1", "iso-8859-1", "iso-8859-15")
diff --git 
a/Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.243aa8.rst 
b/Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.243aa8.rst
new file mode 100644
index 00000000000000..a9452184e7838f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.243aa8.rst
@@ -0,0 +1,2 @@
+Avoid reading past the end of an encoding name when the ``surrogatepass``
+error handler receives a truncated UTF-16 or UTF-32 name.
diff --git a/Python/codecs.c b/Python/codecs.c
index 84a0589c8e8317..8a4d99bdd924fa 100644
--- a/Python/codecs.c
+++ b/Python/codecs.c
@@ -1173,7 +1173,8 @@ get_standard_encoding_impl(const char *encoding, int 
*bytelength)
             }
             if (*encoding == '-' || *encoding == '_' )
                 encoding++;
-            if (Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
+            if (encoding[0] != '\0' &&
+                Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
                 if (Py_TOLOWER(encoding[0]) == 'b')
                     return ENC_UTF16BE;
                 if (Py_TOLOWER(encoding[0]) == 'l')
@@ -1192,7 +1193,8 @@ get_standard_encoding_impl(const char *encoding, int 
*bytelength)
             }
             if (*encoding == '-' || *encoding == '_' )
                 encoding++;
-            if (Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
+            if (encoding[0] != '\0' &&
+                Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
                 if (Py_TOLOWER(encoding[0]) == 'b')
                     return ENC_UTF32BE;
                 if (Py_TOLOWER(encoding[0]) == 'l')

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to