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.
pull/167/head
David Wilson 7 years ago
parent 0eeba2eaa8
commit f752653e77

@ -656,10 +656,11 @@ class LogHandler(logging.Handler):
class Side(object): 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.stream = stream
self.fd = fd self.fd = fd
self.keep_alive = keep_alive self.keep_alive = keep_alive
if cloexec:
set_cloexec(fd) set_cloexec(fd)
set_nonblock(fd) set_nonblock(fd)
@ -1053,14 +1054,13 @@ class IoLogger(BasicStream):
self._broker = broker self._broker = broker
self._name = name self._name = name
self._log = logging.getLogger(name) self._log = logging.getLogger(name)
self._rsock, self._wsock = socket.socketpair() self._rsock, self._wsock = socket.socketpair()
os.dup2(self._wsock.fileno(), dest_fd) os.dup2(self._wsock.fileno(), dest_fd)
set_cloexec(self._rsock.fileno()) set_cloexec(self._rsock.fileno())
set_cloexec(self._wsock.fileno()) set_cloexec(self._wsock.fileno())
self.receive_side = Side(self, self._rsock.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) self._broker.start_receive(self)
def __repr__(self): def __repr__(self):

Loading…
Cancel
Save