8000 bpo-37658: Actually return result in race condition (GH-29202) · python/cpython@934a826 · GitHub
[go: up one dir, main page]

Skip to content

Commit 934a826

Browse files
bpo-37658: Actually return result in race condition (GH-29202)
1 parent f87ea03 commit 934a826

File tree

3 files changed

+13
-36
lines changed

3 files changed

+13
-36
lines changed

Lib/asyncio/tasks.py

Lines changed: 2 additions & 6 deletions
10BC0
Original file line numberDiff line numberDiff line change
@@ -415,11 +415,9 @@ async def wait_for(fut, timeout):
415415

416416
await _cancel_and_wait(fut, loop=loop)
417417
try:
418-
fut.result()
418+
return fut.result()
419419
except exceptions.CancelledError as exc:
420420
raise exceptions.TimeoutError() from exc
421-
else:
422-
raise exceptions.TimeoutError()
423421

424422
waiter = loop.create_future()
425423
timeout_handle = loop.call_later(timeout, _release_waiter, waiter)
@@ -455,11 +453,9 @@ async def wait_for(fut, timeout):
455453
# exception, we should re-raise it
456454
# See https://bugs.python.org/issue40607
457455
try:
458-
fut.result()
456+
return fut.result()
459457
except exceptions.CancelledError as exc:
460458
raise exceptions.TimeoutError() from exc
461-
else:
462-
raise exceptions.TimeoutError()
463459
finally:
464460
timeout_handle.cancel()
465461

Lib/test/test_asyncio/test_tasks.py

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,20 +1009,16 @@ def gen():
10091009
self.assertEqual(res, "ok")
10101010

10111011
def test_wait_for_cancellation_race_condition(self):
1012-
def gen():
1013-
yield 0.1
1014-
yield 0.1
1015-
yield 0.1
1016-
yield 0.1
1012+
async def inner():
1013+
with contextlib.suppress(asyncio.CancelledError):
1014+
await asyncio.sleep(1)
1015+
return 1
10171016

1018-
loop = self.new_test_loop(gen)
1017+
async def main():
1018+
result = await asyncio.wait_for(inner(), timeout=.01)
1019+
assert result == 1
10191020

1020-
fut = self.new_future(loop)
1021-
loop.call_later(0.1, fut.set_result, "ok")
1022-
task = loop.create_task(asyncio.wait_for(fut, timeout=1))
1023-
loop.call_later(0.1, task.cancel)
1024-
res = loop.run_until_complete(task)
1025-
self.assertEqual(res, "ok")
1021+
asyncio.run(main())
10261022

10271023
def test_wait_for_waits_for_task_cancellation(self):
10281024
loop = asyncio.new_event_loop()
@@ -1101,24 +1097,6 @@ async def inner():
11011097
with self.assertRaises(FooException):
11021098
loop.run_until_complete(foo())
11031099

1104-
def test_wait_for_raises_timeout_error_if_returned_during_cancellation(self):
1105-
loop = asyncio.new_event_loop()
1106-
self.addCleanup(loop.close)
1107-
1108-
async def foo():
1109-
async def inner():
1110-
try:
1111-
await asyncio.sleep(0.2)
1112-
except asyncio.CancelledError:
1113-
return 42
1114-
1115-
inner_task = self.new_task(loop, inner())
1116-
1117-
await asyncio.wait_for(inner_task, timeout=_EPSILON)
1118-
1119-
with self.assertRaises(asyncio.TimeoutError):
1120-
loop.run_until_complete(foo())
1121-
11221100
def test_wait_for_self_cancellation(self):
11231101
loop = asyncio.new_event_loop()
11241102
self.addCleanup(loop.close)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix issue when on certain conditions ``asyncio.wait_for()`` may allow a
2+
coroutine to complete successfully, but fail to return the result,
3+
potentially causing memory leaks or other issues.

0 commit comments

Comments
 (0)
0