10000 GH-100573: Fix server hang caused by os.stat() on named pipe (Windows… · python/cpython@1bc7a73 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1bc7a73

Browse files
authored
GH-100573: Fix server hang caused by os.stat() on named pipe (Windows) (#100959)
1 parent c00eb1e commit 1bc7a73

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

Lib/asyncio/windows_events.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,10 @@ def loop_accept_pipe(f=None):
366366
return
367367

368368
f = self._proactor.accept_pipe(pipe)
369+
except BrokenPipeError:
370+
if pipe and pipe.fileno() != -1:
371+
pipe.close()
372+
self.call_soon(loop_accept_pipe)
369373
except OSError as exc:
370374
if pipe and pipe.fileno() != -1:
371375
self.call_exception_handler({
@@ -377,6 +381,7 @@ def loop_accept_pipe(f=None):
377381
elif self._debug:
378382
logger.warning("Accept pipe failed on pipe %r",
379383
pipe, exc_info=True)
384+
self.call_soon(loop_accept_pipe)
380385
except exceptions.CancelledError:
381386
if pipe:
382387
pipe.close()

Lib/test/test_asyncio/test_windows_events.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,46 @@ def test_address_argument_type_error(self):
250250
proactor.sendto(sock, b'abc', addr=bad_address)
251251
sock.close()
252252

253+
def test_client_pipe_stat(self):
254+
res = self.loop.run_until_complete(self._test_client_pipe_stat())
255+
self.assertEqual(res, 'done')
256+
257+
async def _test_client_pipe_stat(self):
258+
# Regression test for https://github.com/python/cpython/issues/100573
259+
ADDRESS = r'\\.\pipe\test_client_pipe_stat-%s' % os.getpid()
260+
261+
async def probe():
262+
# See https://github.com/python/cpython/pull/100959#discussion_r1068533658
263+
h = _overlapped.ConnectPipe(ADDRESS)
264+
try:
265+
_winapi.CloseHandle(_overlapped.ConnectPipe(ADDRESS))
266+
except OSError as e:
267+
if e.winerror != _overlapped.ERROR_PIPE_BUSY:
268+
raise
269+
finally:
270+
_winapi.CloseHandle(h)
271+
272+
with self.assertRaises(FileNotFoundError):
273+
await probe()
274+
275+
[server] = await self.loop.start_serving_pipe(asyncio.Protocol, ADDRESS)
276+
self.assertIsInstance(server, windows_events.PipeServer)
277+
278+
errors = []
279+
self.loop.set_exception_handler(lambda _, data: errors.append(data))
280+
281+
for i in range(5):
282+
await self.loop.create_task(probe())
283+
284+
self.assertEqual(len(errors), 0, errors)
285+
286+
server.close()
287+
288+
with self.assertRaises(FileNotFoundError):
289+
await probe()
290+
291+
return "done"
292+
253293

254294
class WinPolicyTests(test_utils.TestCase):
255295

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a Windows :mod:`asyncio` bug with named pipes where a client doing ``os.stat()`` on the pipe would cause an error in the server that disabled serving future requests.

0 commit comments

Comments
 (0)
0