# HG changeset patch # User Jun Wu # Date 2017-10-03 03:23:25 # Node ID 5385b76fd1fd25668d609eab31726449b96d7965 # Parent b0c97e44576fbf2d3c7f14ff2582f9c67cf47148 zeroconf: do not crash if socket being read is closed by another thread In zeroconf/__init__.py, there is: server = Zeroconf.Zeroconf(ip) l = listener() Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l) time.sleep(1) server.close() `server.close()` closes the underlying socket while the `ServiceBrowser` may still have a background thread reading the socket. There could be a race condition where the reading thread reads the closed socket, resulting in EBADF crash. This patch catches the exception. This makes test-paths.t pass with chg. Differential Revision: https://phab.mercurial-scm.org/D919 diff --git a/hgext/zeroconf/Zeroconf.py b/hgext/zeroconf/Zeroconf.py --- a/hgext/zeroconf/Zeroconf.py +++ b/hgext/zeroconf/Zeroconf.py @@ -80,6 +80,7 @@ from __future__ import absolute_import, __email__ = "paul at scott dash murphy dot com" __version__ = "0.12" +import errno import itertools import select import socket @@ -937,7 +938,16 @@ class Listener(object): self.zeroconf.engine.addReader(self, self.zeroconf.socket) def handle_read(self): - data, (addr, port) = self.zeroconf.socket.recvfrom(_MAX_MSG_ABSOLUTE) + data = addr = port = None + sock = self.zeroconf.socket + try: + data, (addr, port) = sock.recvfrom(_MAX_MSG_ABSOLUTE) + except socket.error as e: + if e.errno == errno.EBADF: + # some other thread may close the socket + return + else: + raise self.data = data msg = DNSIncoming(data) if msg.isQuery():