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>
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.
--- /dev/null
+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.
}
+#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)
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
#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