]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-93251: Decode localized socket error messages from the locale encoding...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sun, 26 Jul 2026 11:35:20 +0000 (13:35 +0200)
committerGitHub <noreply@github.com>
Sun, 26 Jul 2026 11:35:20 +0000 (11:35 +0000)
The gai_strerror() and hstrerror() messages were decoded as UTF-8, so
gaierror and herror could be replaced with UnicodeDecodeError if the
message is localized and the locale encoding is not UTF-8.
(cherry picked from commit 5afbb60e0283caaf34990bbe8437111ebaae04a4)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Lib/test/test_socket.py
Misc/NEWS.d/next/Library/2026-07-25-13-30-00.gh-issue-93251.gAiErr.rst [new file with mode: 0644]
Modules/socketmodule.c

index a0943a6e58e95ad78d08c8bba588381a414ff519..2eba9dcd2bfe5381e1abad9251acc86cdb345bcb 100644 (file)
@@ -1732,6 +1732,22 @@ class GeneralModuleTests(unittest.TestCase):
             except socket.gaierror:
                 pass
 
+    @unittest.skipUnless(hasattr(socket, 'AI_NUMERICSERV'),
+                         'needs socket.AI_NUMERICSERV')
+    @support.run_with_locales('LC_ALL',
+        'uk_UA.KOI8-U', 'uk_UA', 'ja_JP.eucJP', 'ja_JP.SJIS', 'ja_JP',
+        'ko_KR.eucKR', 'zh_CN.GB18030', 'el_GR.ISO8859-7',
+        'de_DE.ISO8859-1', 'ja_JP.UTF-8',
+        '')
+    def test_getaddrinfo_localized_error(self):
+        # gh-93251: the localized gai_strerror() message could fail to be
+        # decoded as UTF-8, so UnicodeDecodeError was raised
+        # instead of gaierror.
+        with self.assertRaises(socket.gaierror) as cm:
+            socket.getaddrinfo("localhost", "http",
+                               flags=socket.AI_NUMERICSERV)
+        str(cm.exception)
+
     @unittest.skipIf(_testcapi is None, "requires _testcapi")
     def test_getaddrinfo_int_port_overflow(self):
         # gh-74895: Test that getaddrinfo does not raise OverflowError on port.
diff --git a/Misc/NEWS.d/next/Library/2026-07-25-13-30-00.gh-issue-93251.gAiErr.rst b/Misc/NEWS.d/next/Library/2026-07-25-13-30-00.gh-issue-93251.gAiErr.rst
new file mode 100644 (file)
index 0000000..3f31303
--- /dev/null
@@ -0,0 +1,4 @@
+Fix :exc:`UnicodeDecodeError` in :mod:`socket` functions
+(such as :func:`~socket.getaddrinfo` and :func:`~socket.gethostbyaddr`)
+when the localized error message of the C library is not UTF-8:
+decode it from the locale encoding.
index 8008c101251c6607c33a7e81222a136342839d35..d7e36c027405c8cc45d53017567c8f7ddf188fc3 100644 (file)
@@ -676,6 +676,16 @@ set_error(void)
 }
 
 
+#if defined(HAVE_HSTRERROR) || defined(HAVE_GAI_STRERROR)
+/* Decode a locale-encoded error message from the C library.
+   It can be localized and use a non-UTF-8 encoding. */
+static PyObject *
+decode_error_message(const char *str)
+{
+    return PyUnicode_DecodeLocale(str, "surrogateescape");
+}
+#endif
+
 #if defined(HAVE_GETHOSTBYNAME_R) || defined (HAVE_GETHOSTBYNAME) || defined (HAVE_GETHOSTBYADDR)
 static PyObject *
 set_herror(socket_state *state, int h_error)
@@ -683,7 +693,7 @@ set_herror(socket_state *state, int h_error)
     PyObject *v;
 
 #ifdef HAVE_HSTRERROR
-    v = Py_BuildValue("(is)", h_error, hstrerror(h_error));
+    v = Py_BuildValue("(iN)", h_error, decode_error_message(hstrerror(h_error)));
 #else
     v = Py_BuildValue("(is)", h_error, "host not found");
 #endif
@@ -710,7 +720,7 @@ set_gaierror(socket_state *state, int error)
 #endif
 
 #ifdef HAVE_GAI_STRERROR
-    v = Py_BuildValue("(is)", error, gai_strerror(error));
+    v = Py_BuildValue("(iN)", error, decode_error_message(gai_strerror(error)));
 #else
     v = Py_BuildValue("(is)", error, "getaddrinfo failed");
 #endif