mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +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: | ||||
|                 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) | ||||
|  |  | |||
|  | @ -1688,6 +1688,7 @@ Roman Skurikhin | |||
| Ville Skyttä | ||||
| Michael Sloan | ||||
| Nick Sloan | ||||
| Radek Smejkal | ||||
| Václav Šmilauer | ||||
| Casper W. Smet | ||||
| 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_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; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Radek Smejkal
						Radek Smejkal