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

Skip to content

Commit df3b74e

Browse files
committed
gh-111246: Don't remove stolen Unix socket address (#111246)
We only want to clean up *our* socket, so try to determine if we still own this address or if something else has replaced it.
1 parent 21e9d8c commit df3b74e

File tree

3 files changed

+31
-8
lines changed

3 files changed

+31
-8
lines changed

Doc/library/asyncio-eventloop.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,8 @@ Creating network servers
803803
.. versionchanged:: 3.13
804804

805805
The Unix socket will automatically be removed from the filesystem
806-
when the server is closed.
806+
when the server is closed, unless the socket has been replaced
807+
after the server has been created.
807808

808809

809810
.. coroutinemethod:: loop.connect_accepted_socket(protocol_factory, \

Lib/asyncio/unix_events.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop):
6464
def __init__(self, selector=None):
6565
super().__init__(selector)
6666
self._signal_handlers = {}
67+
self._unix_server_sockets = {}
6768

6869
def close(self):
6970
super().close()
@@ -340,6 +341,14 @@ async def create_unix_server(
340341
raise ValueError(
341342
f'A UNIX Domain Stream Socket was expected, got {sock!r}')
342343

344+
path = sock.getsockname()
345+
# Check for abstract socket. `str` and `bytes` paths are supported.
346+
if path[0] not in (0, '\x00'):
347+
try:
348+
self._unix_server_sockets[sock] = os.stat(path).st_ino
349+
except FileNotFoundError:
350+
pass
351+
343352
sock.setblocking(False)
344353
server = base_events.Server(self, [sock], protocol_factory,
345354
ssl, backlog, ssl_handshake_timeout,
@@ -462,21 +471,19 @@ def cb(fut):
462471

463472
def _stop_serving(self, sock):
464473
# Is this a unix socket that needs cleanup?
465-
if sock.family == socket.AF_UNIX:
474+
if sock in self._unix_server_sockets:
466475
path = sock.getsockname()
467-
if path == '':
468-
path = None
469-
# Check for abstract socket. `str` and `bytes` paths are supported.
470-
elif path[0] in (0, '\x00'):
471-
path = None
472476
else:
473477
path = None
474478

475479
super()._stop_serving(sock)
476480

477481
if path is not None:
482+
prev_ino = self._unix_server_sockets[sock]
483+
del self._unix_server_sockets[sock]
478484
try:
479-
os.unlink(path)
485+
if os.stat(path).st_ino == prev_ino:
486+
os.unlink(path)
480487
except FileNotFoundError:
481488
pass
482489
except OSError as err:

Lib/test/test_asyncio/test_server.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,21 @@ async def serve(*args):
190190

191191
srv.close()
192192

193+
@socket_helper.skip_unless_bind_unix_socket
194+
async def test_unix_server_cleanup_replaced(self):
195+
with test_utils.unix_socket_path() as addr:
196+
async def serve(*args):
197+
pass
198+
199+
srv = await asyncio.start_unix_server(serve, addr)
200+
201+
os.unlink(addr)
202+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
203+
sock.bind(addr)
204+
205+
srv.close()
206+
self.assertTrue(os.path.exists(addr))
207+
193208

194209
@unittest.skipUnless(hasattr(asyncio, 'ProactorEventLoop'), 'Windows only')
195210
class ProactorStartServerTests(BaseStartServer, unittest.TestCase):

0 commit comments

Comments
 (0)