Skip to content
6 changes: 5 additions & 1 deletion Lib/socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,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):
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -3195,6 +3195,22 @@ def testFromFd(self):
def _testFromFd(self):
self.serv_conn.send(MSG)

def testFromFdError(self):
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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use os_helper.fd_count() which works on all platforms. I suggest a shorter test name and more flat code to trigger errors:

Suggested change
def testFromFdError(self):
# Make sure that the fromfd() duplicated socket is closed on error.
# In debug mode, Python test suite checks for file descriptor leaks.
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_UNIX, "not-a-valid-type")
with self.assertRaises(OverflowError):
socket.fromfd(fd, socket.AF_UNIX, 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()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a descriptor leak in :func:`socket.fromfd` when the socket constructor rejects its arguments. The duplicated descriptor was never closed.
Loading