Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bcb39d4

Browse files
committed
Issue #11657: Fix sending file descriptors over 255 over a multiprocessing Pipe.
Also added some tests.
1 parent 5bd8b8d commit bcb39d4

3 files changed

Lines changed: 86 additions & 3 deletions

File tree

Lib/test/test_multiprocessing.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,19 @@
3535
import multiprocessing.heap
3636
import multiprocessing.pool
3737

38-
from multiprocessing import util
38+
from multiprocessing import util, reduction
3939

4040
try:
4141
from multiprocessing.sharedctypes import Value, copy
4242
HAS_SHAREDCTYPES = True
4343
except ImportError:
4444
HAS_SHAREDCTYPES = False
4545

46+
try:
47+
import msvcrt
48+
except ImportError:
49+
msvcrt = None
50+
4651
#
4752
#
4853
#
@@ -72,6 +77,11 @@ def latin(s):
7277

7378
WIN32 = (sys.platform == "win32")
7479

80+
try:
81+
MAXFD = os.sysconf("SC_OPEN_MAX")
82+
except:
83+
MAXFD = 256
84+
7585
#
7686
# Some tests require ctypes
7787
#
@@ -1538,6 +1548,76 @@ def test_sendbytes(self):
15381548

15391549
self.assertRaises(ValueError, a.send_bytes, msg, 4, -1)
15401550

1551+
@classmethod
1552+
def _is_fd_assigned(cls, fd):
1553+
try:
1554+
os.fstat(fd)
1555+
except OSError as e:
1556+
if e.errno == errno.EBADF:
1557+
return False
1558+
raise
1559+
else:
1560+
return True
1561+
1562+
@classmethod
1563+
def _writefd(cls, conn, data, create_dummy_fds=False):
1564+
if create_dummy_fds:
1565+
for i in range(0, 256):
1566+
if not cls._is_fd_assigned(i):
1567+
os.dup2(conn.fileno(), i)
1568+
fd = reduction.recv_handle(conn)
1569+
if msvcrt:
1570+
fd = msvcrt.open_osfhandle(fd, os.O_WRONLY)
1571+
os.write(fd, data)
1572+
os.close(fd)
1573+
1574+
def test_fd_transfer(self):
1575+
if self.TYPE != 'processes':
1576+
self.skipTest("only makes sense with processes")
1577+
conn, child_conn = self.Pipe(duplex=True)
1578+
1579+
p = self.Process(target=self._writefd, args=(child_conn, b"foo"))
1580+
p.start()
1581+
with open(test.support.TESTFN, "wb") as f:
1582+
fd = f.fileno()
1583+
if msvcrt:
1584+
fd = msvcrt.get_osfhandle(fd)
1585+
reduction.send_handle(conn, fd, p.pid)
1586+
p.join()
1587+
with open(test.support.TESTFN, "rb") as f:
1588+
self.assertEqual(f.read(), b"foo")
1589+
1590+
@unittest.skipIf(sys.platform == "win32",
1591+
"test semantics don't make sense on Windows")
1592+
@unittest.skipIf(MAXFD <= 256,
1593+
"largest assignable fd number is too small")
1594+
@unittest.skipUnless(hasattr(os, "dup2"),
1595+
"test needs os.dup2()")
1596+
def test_large_fd_transfer(self):
1597+
# With fd > 256 (issue #11657)
1598+
if self.TYPE != 'processes':
1599+
self.skipTest("only makes sense with processes")
1600+
conn, child_conn = self.Pipe(duplex=True)
1601+
1602+
p = self.Process(target=self._writefd, args=(child_conn, b"bar", True))
1603+
p.start()
1604+
with open(test.support.TESTFN, "wb") as f:
1605+
fd = f.fileno()
1606+
for newfd in range(256, MAXFD):
1607+
if not self._is_fd_assigned(newfd):
1608+
break
1609+
else:
1610+
self.fail("could not find an unassigned large file descriptor")
1611+
os.dup2(fd, newfd)
1612+
try:
1613+
reduction.send_handle(conn, newfd, p.pid)
1614+
finally:
1615+
os.close(newfd)
1616+
p.join()
1617+
with open(test.support.TESTFN, "rb") as f:
1618+
self.assertEqual(f.read(), b"bar")
1619+
1620+
15411621
class _TestListenerClient(BaseTestCase):
15421622

15431623
ALLOWED_TYPES = ('processes', 'threads')

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Core and Builtins
2222
Library
2323
-------
2424

25+
- Issue #11657: Fix sending file descriptors over 255 over a multiprocessing
26+
Pipe.
27+
2528
- Issue #12213: Fix a buffering bug with interleaved reads and writes that
2629
could appear on BufferedRandom streams.
2730

Modules/_multiprocessing/multiprocessing.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ multiprocessing_sendfd(PyObject *self, PyObject *args)
122122
cmsg->cmsg_type = SCM_RIGHTS;
123123
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
124124
msg.msg_controllen = cmsg->cmsg_len;
125-
*CMSG_DATA(cmsg) = fd;
125+
* (int *) CMSG_DATA(cmsg) = fd;
126126

127127
Py_BEGIN_ALLOW_THREADS
128128
res = sendmsg(conn, &msg, 0);
@@ -165,7 +165,7 @@ multiprocessing_recvfd(PyObject *self, PyObject *args)
165165
if (res < 0)
166166
return PyErr_SetFromErrno(PyExc_OSError);
167167

168-
fd = *CMSG_DATA(cmsg);
168+
fd = * (int *) CMSG_DATA(cmsg);
169169
return Py_BuildValue("i", fd);
170170
}
171171

0 commit comments

Comments
 (0)