[Python-checkins] gh-74895: getaddrinfo no longer raises OverflowError (#2435)
gpshead
webhook-mailer at python.org
Mon Feb 13 20:38:10 EST 2023
https://github.com/python/cpython/commit/928752ce4c23f47d3175dd47ecacf08d86a99c9d
commit: 928752ce4c23f47d3175dd47ecacf08d86a99c9d
branch: main
author: Radek Smejkal <radek.smejkal at atrak.cz>
committer: gpshead <greg at krypto.org>
date: 2023-02-13T17:37:34-08:00
summary:
gh-74895: getaddrinfo no longer raises OverflowError (#2435)
`socket.getaddrinfo()` no longer raises `OverflowError` based on the **port** argument. Error reporting (or not) for its value is left up to the underlying C library `getaddrinfo()` implementation.
files:
A Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst
M Lib/test/test_socket.py
M Misc/ACKS
M Modules/getaddrinfo.c
M Modules/socketmodule.c
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index f1b4018c265e..a313da29b4a4 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1600,6 +1600,54 @@ def testGetaddrinfo(self):
except socket.gaierror:
pass
+ def test_getaddrinfo_int_port_overflow(self):
+ # gh-74895: Test that getaddrinfo does not raise OverflowError on port.
+ #
+ # POSIX getaddrinfo() never specify the valid range for "service"
+ # decimal port number values. For IPv4 and IPv6 they are technically
+ # unsigned 16-bit values, but the API is protocol agnostic. Which values
+ # trigger an error from the C library function varies by platform as
+ # they do not all perform validation.
+
+ # The key here is that we don't want to produce OverflowError as Python
+ # prior to 3.12 did for ints outside of a [LONG_MIN, LONG_MAX] range.
+ # Leave the error up to the underlying string based platform C API.
+
+ from _testcapi import ULONG_MAX, LONG_MAX, LONG_MIN
+ try:
+ socket.getaddrinfo(None, ULONG_MAX + 1)
+ except OverflowError:
+ # Platforms differ as to what values consitute a getaddrinfo() error
+ # return. Some fail for LONG_MAX+1, others ULONG_MAX+1, and Windows
+ # silently accepts such huge "port" aka "service" numeric values.
+ self.fail("Either no error or socket.gaierror expected.")
+ except socket.gaierror:
+ pass
+
+ try:
+ socket.getaddrinfo(None, LONG_MAX + 1)
+ except OverflowError:
+ self.fail("Either no error or socket.gaierror expected.")
+ except socket.gaierror:
+ pass
+
+ try:
+ socket.getaddrinfo(None, LONG_MAX - 0xffff + 1)
+ except OverflowError:
+ self.fail("Either no error or socket.gaierror expected.")
+ except socket.gaierror:
+ pass
+
+ try:
+ socket.getaddrinfo(None, LONG_MIN - 1)
+ except OverflowError:
+ self.fail("Either no error or socket.gaierror expected.")
+ except socket.gaierror:
+ pass
+
+ socket.getaddrinfo(None, 0) # No error expected.
+ socket.getaddrinfo(None, 0xffff) # No error expected.
+
def test_getnameinfo(self):
# only IP addresses are allowed
self.assertRaises(OSError, socket.getnameinfo, ('mail.python.org',0), 0)
diff --git a/Misc/ACKS b/Misc/ACKS
index e12cbea0ebd6..ca92608868f2 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1688,6 +1688,7 @@ Roman Skurikhin
Ville Skyttä
Michael Sloan
Nick Sloan
+Radek Smejkal
Václav Šmilauer
Casper W. Smet
Allen W. Smith
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst
new file mode 100644
index 000000000000..adbbb601634a
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst
@@ -0,0 +1,5 @@
+:mod:`socket.getaddrinfo` no longer raises :class:`OverflowError` for
+:class:`int` **port** values outside of the C long range. Out of range values
+are left up to the underlying string based C library API to report. A
+:class:`socket.gaierror` ``SAI_SERVICE`` may occur instead, or no error at all
+as not all platform C libraries generate an error.
diff --git a/Modules/getaddrinfo.c b/Modules/getaddrinfo.c
index 0b4620ed683d..f1c28d7d9312 100644
--- a/Modules/getaddrinfo.c
+++ b/Modules/getaddrinfo.c
@@ -342,7 +342,11 @@ getaddrinfo(const char*hostname, const char*servname,
pai->ai_socktype = SOCK_DGRAM;
pai->ai_protocol = IPPROTO_UDP;
}
- port = htons((u_short)atoi(servname));
+ long maybe_port = strtol(servname, NULL, 10);
+ if (maybe_port < 0 || maybe_port > 0xffff) {
+ ERR(EAI_SERVICE);
+ }
+ port = htons((u_short)maybe_port);
} else {
struct servent *sp;
const char *proto;
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 0a9e46512b15..2d300f19436b 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -6650,7 +6650,7 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
struct addrinfo *res0 = NULL;
PyObject *hobj = NULL;
PyObject *pobj = (PyObject *)NULL;
- char pbuf[30];
+ PyObject *pstr = NULL;
const char *hptr, *pptr;
int family, socktype, protocol, flags;
int error;
@@ -6680,11 +6680,13 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
return NULL;
}
if (PyLong_CheckExact(pobj)) {
- long value = PyLong_AsLong(pobj);
- if (value == -1 && PyErr_Occurred())
+ pstr = PyObject_Str(pobj);
+ if (pstr == NULL)
+ goto err;
+ assert(PyUnicode_Check(pstr));
+ pptr = PyUnicode_AsUTF8(pstr);
+ if (pptr == NULL)
goto err;
- PyOS_snprintf(pbuf, sizeof(pbuf), "%ld", value);
- pptr = pbuf;
} else if (PyUnicode_Check(pobj)) {
pptr = PyUnicode_AsUTF8(pobj);
if (pptr == NULL)
@@ -6750,12 +6752,14 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
Py_DECREF(single);
}
Py_XDECREF(idna);
+ Py_XDECREF(pstr);
if (res0)
freeaddrinfo(res0);
return all;
err:
Py_XDECREF(all);
Py_XDECREF(idna);
+ Py_XDECREF(pstr);
if (res0)
freeaddrinfo(res0);
return (PyObject *)NULL;
More information about the Python-checkins
mailing list