]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-126876: Fix socket internal_select() for large timeout (GH-126968) (#127002)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 2 Dec 2024 16:25:55 +0000 (17:25 +0100)
committerGitHub <noreply@github.com>
Mon, 2 Dec 2024 16:25:55 +0000 (16:25 +0000)
gh-126876: Fix socket internal_select() for large timeout (GH-126968)

If the timeout is larger than INT_MAX, replace it with INT_MAX, in
the poll() code path.

Add an unit test.
(cherry picked from commit b3687ad454c4ac54c8599a10f3ace8a13ca48915)

Co-authored-by: Victor Stinner <vstinner@python.org>
Lib/test/test_socket.py
Modules/socketmodule.c

index e351ccdf057e9af65138730045114818e5a5f6a9..28764536fa0400ec1519ae2f5e3b0f6f90253013 100644 (file)
@@ -5126,6 +5126,39 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
         # send data: recv() will no longer block
         self.cli.sendall(MSG)
 
+    def testLargeTimeout(self):
+        # gh-126876: Check that a timeout larger than INT_MAX is replaced with
+        # INT_MAX in the poll() code path. The following assertion must not
+        # fail: assert(INT_MIN <= ms && ms <= INT_MAX).
+        if _testcapi is not None:
+            large_timeout = _testcapi.INT_MAX + 1
+        else:
+            large_timeout = 2147483648
+
+        # test recv() with large timeout
+        conn, addr = self.serv.accept()
+        self.addCleanup(conn.close)
+        try:
+            conn.settimeout(large_timeout)
+        except OverflowError:
+            # On Windows, settimeout() fails with OverflowError, whereas
+            # we want to test recv(). Just give up silently.
+            return
+        msg = conn.recv(len(MSG))
+
+    def _testLargeTimeout(self):
+        # test sendall() with large timeout
+        if _testcapi is not None:
+            large_timeout = _testcapi.INT_MAX + 1
+        else:
+            large_timeout = 2147483648
+        self.cli.connect((HOST, self.port))
+        try:
+            self.cli.settimeout(large_timeout)
+        except OverflowError:
+            return
+        self.cli.sendall(MSG)
+
 
 class FileObjectClassTestCase(SocketConnectedTest):
     """Unit tests for the object returned by socket.makefile()
index daec560ddfcac706533417a293abee88fb563bbc..1c0bc7967321201f9cce07a5311d183cd687ba3c 100644 (file)
@@ -810,7 +810,9 @@ internal_select(PySocketSockObject *s, int writing, PyTime_t interval,
 
     /* s->sock_timeout is in seconds, timeout in ms */
     ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING);
-    assert(ms <= INT_MAX);
+    if (ms > INT_MAX) {
+        ms = INT_MAX;
+    }
 
     /* On some OSes, typically BSD-based ones, the timeout parameter of the
        poll() syscall, when negative, must be exactly INFTIM, where defined,
@@ -822,6 +824,7 @@ internal_select(PySocketSockObject *s, int writing, PyTime_t interval,
         ms = -1;
 #endif
     }
+    assert(INT_MIN <= ms && ms <= INT_MAX);
 
     Py_BEGIN_ALLOW_THREADS;
     n = poll(&pollfd, 1, (int)ms);