From 99263a1dec97280dce16b22eae4a73d0aa7e2423 Mon Sep 17 00:00:00 2001 From: scrieve <86650480+scrieve@users.noreply.github.com> Date: Tue, 27 Oct 2026 22:56:42 +0000 Subject: [PATCH] gh-160561: Close the duplicated descriptor when socket.fromfd() fails (GH-160579) (cherry picked from commit 6c695bfad45ddde73d0d674286800fbe295f0627) Co-authored-by: scrieve <86650480+scrieve@users.noreply.github.com> Co-authored-by: wlkr73 <86650480+wlkr73@users.noreply.github.com> Co-authored-by: lumenyr <86650480+lumenyr@users.noreply.github.com> Co-authored-by: Victor Stinner --- Lib/socket.py | 6 +++++- Lib/test/test_socket.py | 17 +++++++++++++++++ ...26-10-24-07-58-00.gh-issue-160561.b3Kq1z.rst | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-24-07-58-00.gh-issue-160561.b3Kq1z.rst diff --git a/Lib/socket.py b/Lib/socket.py index 9ac0badc6606c19..1dc80724817af5f 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -552,7 +552,11 @@ def fromfd(fd, family, type, proto=0): descriptor. The remaining arguments are the same as for socket(). """ nfd = dup(fd) - return socket(family, type, proto, nfd) + try: + return socket(family, type, proto, nfd) + except: + close(nfd) + raise if hasattr(_socket.socket, "sendmsg"): def send_fds(sock, buffers, fds, flags=0, address=None): diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 4b29273b7a240a0..3d7be767a8bb29a 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3090,6 +3090,23 @@ def testFromFd(self): def _testFromFd(self): self.serv_conn.send(MSG) + def testFromFdError(self): + # Make sure that the fromfd() duplicated socket is closed on error. + fd = self.cli_conn.fileno() + fd_count_before = os_helper.fd_count() + + with self.assertRaises(TypeError): + socket.fromfd(fd, "not-a-valid-family", socket.SOCK_STREAM) + with self.assertRaises(TypeError): + socket.fromfd(fd, socket.AF_INET, "not-a-valid-type") + with self.assertRaises(OverflowError): + socket.fromfd(fd, socket.AF_INET, 1 << 100) + + self.assertEqual(os_helper.fd_count(), fd_count_before) + + def _testFromFdError(self): + pass + def testDup(self): # Testing dup() sock = self.cli_conn.dup() diff --git a/Misc/NEWS.d/next/Library/2026-10-24-07-58-00.gh-issue-160561.b3Kq1z.rst b/Misc/NEWS.d/next/Library/2026-10-24-07-58-00.gh-issue-160561.b3Kq1z.rst new file mode 100644 index 000000000000000..c49cd6a83e90bf4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-24-07-58-00.gh-issue-160561.b3Kq1z.rst @@ -0,0 +1 @@ +Fix a descriptor leak in :func:`socket.fromfd` when the socket constructor rejects its arguments. The duplicated descriptor was never closed.