D919: zeroconf: do not crash if socket being read is closed by another thread

quark (Jun Wu) phabricator at mercurial-scm.org
Tue Oct 3 03:23:52 UTC 2017


quark created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  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.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D919

AFFECTED FILES
  hgext/zeroconf/Zeroconf.py

CHANGE DETAILS

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 @@
 __email__ = "paul at scott dash murphy dot com"
 __version__ = "0.12"
 
+import errno
 import itertools
 import select
 import socket
@@ -937,7 +938,16 @@
         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():



To: quark, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list