mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									0c6fe81dce
								
							
						
					
					
						commit
						928752ce4c
					
				
					 5 changed files with 68 additions and 6 deletions
				
			
		|  | @ -1600,6 +1600,54 @@ def testGetaddrinfo(self): | ||||||
|             except socket.gaierror: |             except socket.gaierror: | ||||||
|                 pass |                 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): |     def test_getnameinfo(self): | ||||||
|         # only IP addresses are allowed |         # only IP addresses are allowed | ||||||
|         self.assertRaises(OSError, socket.getnameinfo, ('mail.python.org',0), 0) |         self.assertRaises(OSError, socket.getnameinfo, ('mail.python.org',0), 0) | ||||||
|  |  | ||||||
|  | @ -1688,6 +1688,7 @@ Roman Skurikhin | ||||||
| Ville Skyttä | Ville Skyttä | ||||||
| Michael Sloan | Michael Sloan | ||||||
| Nick Sloan | Nick Sloan | ||||||
|  | Radek Smejkal | ||||||
| Václav Šmilauer | Václav Šmilauer | ||||||
| Casper W. Smet | Casper W. Smet | ||||||
| Allen W. Smith | Allen W. Smith | ||||||
|  |  | ||||||
|  | @ -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. | ||||||
|  | @ -342,7 +342,11 @@ getaddrinfo(const char*hostname, const char*servname, | ||||||
|                 pai->ai_socktype = SOCK_DGRAM; |                 pai->ai_socktype = SOCK_DGRAM; | ||||||
|                 pai->ai_protocol = IPPROTO_UDP; |                 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 { |         } else { | ||||||
|             struct servent *sp; |             struct servent *sp; | ||||||
|             const char *proto; |             const char *proto; | ||||||
|  |  | ||||||
|  | @ -6650,7 +6650,7 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs) | ||||||
|     struct addrinfo *res0 = NULL; |     struct addrinfo *res0 = NULL; | ||||||
|     PyObject *hobj = NULL; |     PyObject *hobj = NULL; | ||||||
|     PyObject *pobj = (PyObject *)NULL; |     PyObject *pobj = (PyObject *)NULL; | ||||||
|     char pbuf[30]; |     PyObject *pstr = NULL; | ||||||
|     const char *hptr, *pptr; |     const char *hptr, *pptr; | ||||||
|     int family, socktype, protocol, flags; |     int family, socktype, protocol, flags; | ||||||
|     int error; |     int error; | ||||||
|  | @ -6680,11 +6680,13 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs) | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     if (PyLong_CheckExact(pobj)) { |     if (PyLong_CheckExact(pobj)) { | ||||||
|         long value = PyLong_AsLong(pobj); |         pstr = PyObject_Str(pobj); | ||||||
|         if (value == -1 && PyErr_Occurred()) |         if (pstr == NULL) | ||||||
|  |             goto err; | ||||||
|  |         assert(PyUnicode_Check(pstr)); | ||||||
|  |         pptr = PyUnicode_AsUTF8(pstr); | ||||||
|  |         if (pptr == NULL) | ||||||
|             goto err; |             goto err; | ||||||
|         PyOS_snprintf(pbuf, sizeof(pbuf), "%ld", value); |  | ||||||
|         pptr = pbuf; |  | ||||||
|     } else if (PyUnicode_Check(pobj)) { |     } else if (PyUnicode_Check(pobj)) { | ||||||
|         pptr = PyUnicode_AsUTF8(pobj); |         pptr = PyUnicode_AsUTF8(pobj); | ||||||
|         if (pptr == NULL) |         if (pptr == NULL) | ||||||
|  | @ -6750,12 +6752,14 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs) | ||||||
|         Py_DECREF(single); |         Py_DECREF(single); | ||||||
|     } |     } | ||||||
|     Py_XDECREF(idna); |     Py_XDECREF(idna); | ||||||
|  |     Py_XDECREF(pstr); | ||||||
|     if (res0) |     if (res0) | ||||||
|         freeaddrinfo(res0); |         freeaddrinfo(res0); | ||||||
|     return all; |     return all; | ||||||
|  err: |  err: | ||||||
|     Py_XDECREF(all); |     Py_XDECREF(all); | ||||||
|     Py_XDECREF(idna); |     Py_XDECREF(idna); | ||||||
|  |     Py_XDECREF(pstr); | ||||||
|     if (res0) |     if (res0) | ||||||
|         freeaddrinfo(res0); |         freeaddrinfo(res0); | ||||||
|     return (PyObject *)NULL; |     return (PyObject *)NULL; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Radek Smejkal
						Radek Smejkal