From f752653e7702c50375c71b8d54ccd95ee4947b5d Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sat, 24 Mar 2018 18:35:27 +0545 Subject: [PATCH] core: IoLogger: don't set O_CLOEXEC on standard handles nested_test was failing due to the recent change to centralize O_CLOEXEC, since stdout and stderr were being marked as non-inheritable. That meant child processes would start with no stdout/stderr, triggering a race between Waker opening its pipes, and IoLogger dup2'ing its pipes over the stdio handles. Since the stdio handles were closed, Waker would receive one of them as one end of its pipe, and consequently have it overwritten by IoLogger. When IoLogger dups over the top of fd 2, it becomes possible for Waker.on_read() to be called due to pipe's other end to be closed, causing an OSError exception with errno EAGAIN to appear. --- mitogen/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mitogen/core.py b/mitogen/core.py index b0741cd8..e20a742e 100644 --- a/mitogen/core.py +++ b/mitogen/core.py @@ -656,11 +656,12 @@ class LogHandler(logging.Handler): class Side(object): - def __init__(self, stream, fd, keep_alive=True): + def __init__(self, stream, fd, cloexec=True, keep_alive=True): self.stream = stream self.fd = fd self.keep_alive = keep_alive - set_cloexec(fd) + if cloexec: + set_cloexec(fd) set_nonblock(fd) def __repr__(self): @@ -1053,14 +1054,13 @@ class IoLogger(BasicStream): self._broker = broker self._name = name self._log = logging.getLogger(name) - self._rsock, self._wsock = socket.socketpair() os.dup2(self._wsock.fileno(), dest_fd) set_cloexec(self._rsock.fileno()) set_cloexec(self._wsock.fileno()) self.receive_side = Side(self, self._rsock.fileno()) - self.transmit_side = Side(self, dest_fd) + self.transmit_side = Side(self, dest_fd, cloexec=False) self._broker.start_receive(self) def __repr__(self):