https://github.com/python/cpython/commit/5afbb60e0283caaf34990bbe8437111ebaae04a4
commit: 5afbb60e0283caaf34990bbe8437111ebaae04a4
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-26T12:31:26+03:00
summary:

gh-93251: Decode localized socket error messages from the locale encoding 
(GH-154683)

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.

Co-authored-by: Claude Fable 5 <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-07-25-13-30-00.gh-issue-93251.gAiErr.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index a234d6b37ff379..7bb50f7b8aa47e 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1787,6 +1787,23 @@ def testGetaddrinfo(self):
             except socket.gaierror:
                 pass
 
+    @unittest.skipUnless(hasattr(socket, 'AI_NUMERICSERV'),
+                         'needs socket.AI_NUMERICSERV')
+    @support.thread_unsafe('setlocale is not thread-safe')
+    @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
index 00000000000000..3f313030802f87
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-25-13-30-00.gh-issue-93251.gAiErr.rst
@@ -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.
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 084c2dbcff066e..73ae1c942daba4 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -745,6 +745,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)
@@ -752,7 +762,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
@@ -779,7 +789,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

_______________________________________________
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