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

Skip to content

Commit 305236e

Browse files
bpo-37658: Actually return result in race condition (GH-29202)
(cherry picked from commit 934a826) Co-authored-by: Sam Bull <aa6bs0@sambull.org>
1 parent 8d1a580 commit 305236e

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
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
@@ -1148,20 +1148,16 @@ def gen():
11481148
self.assertEqual(res, "ok")
11491149

11501150
def test_wait_for_cancellation_race_condition(self):
1151-
def gen():
1152-
yield 0.1
1153-
yield 0.1
1154-
yield 0.1
1155-
yield 0.1
1151+
async def inner():
1152+
with contextlib.suppress(asyncio.CancelledError):
1153+
await asyncio.sleep(1)
1154+
return 1
11561155

1157-
loop = self.new_test_loop(gen)
1156+
async def main():
1157+
result = await asyncio.wait_for(inner(), timeout=.01)
1158+
assert result == 1
11581159

1159-
fut = self.new_future(loop)
1160-
loop.call_later(0.1, fut.set_result, "ok")
1161-
task = loop.create_task(asyncio.wait_for(fut, timeout=1))
1162-
loop.call_later(0.1, task.cancel)
1163-
res = loop.run_until_complete(task)
1164-
self.assertEqual(res, "ok")
1160+
asyncio.run(main())
11651161

11661162
def test_wait_for_waits_for_task_cancellation(self):
11671163
loop = asyncio.new_event_loop()
@@ -1240,24 +1236,6 @@ async def inner():
12401236
with self.assertRaises(FooException):
12411237
loop.run_until_complete(foo())
12421238

1243-
def test_wait_for_raises_timeout_error_if_returned_during_cancellation(self):
1244-
loop = asyncio.new_event_loop()
1245-
self.addCleanup(loop.close)
1246-
1247-
async def foo():
1248-
async def inner():
1249-
try:
1250-
await asyncio.sleep(0.2)
1251-
except asyncio.CancelledError:
1252-
return 42
1253-
1254-
inner_task = self.new_task(loop, inner())
1255-
1256-
await asyncio.wait_for(inner_task, timeout=_EPSILON)
1257-
1258-
with self.assertRaises(asyncio.TimeoutError):
1259-
loop.run_until_complete(foo())
1260-
12611239
def test_wait_for_self_cancellation(self):
12621240
loop = asyncio.new_event_loop()
12631241
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