]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-152569: Fix asyncio.wait leaking tasks via await-graph on long-lived futures ...
authorSimon Knott <info@simonknott.de>
Thu, 2 Jul 2026 07:50:12 +0000 (09:50 +0200)
committerGitHub <noreply@github.com>
Thu, 2 Jul 2026 07:50:12 +0000 (13:20 +0530)
Lib/asyncio/tasks.py
Lib/test/test_asyncio/test_tasks.py
Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst [new file with mode: 0644]

index 14d3c1ceb58cacb6e99f9d1f239835d7b265e597..9d20930dc300c6752dae6922022238b3eb684416 100644 (file)
@@ -524,6 +524,7 @@ async def _wait(fs, timeout, return_when, loop):
             timeout_handle.cancel()
         for f in fs:
             f.remove_done_callback(_on_completion)
+            futures.future_discard_from_awaited_by(f, cur_task)
 
     done, pending = set(), set()
     for f in fs:
index 7a217f886b87de271667284870e502a2d1b08d75..609ccdbfdb2b28900817c873aeea5340c6615e3c 100644 (file)
@@ -1218,6 +1218,19 @@ class BaseTaskTests:
         loop.advance_time(10)
         loop.run_until_complete(asyncio.wait([a, b]))
 
+    def test_wait_discards_awaited_by_for_pending(self):
+        # gh-152569: wait() must remove itself from the await-graph of every
+        # future once it returns, including futures that never resolved.
+        async def coro():
+            immortal = self.loop.create_future()
+            done = self.new_task(self.loop, asyncio.sleep(0))
+            await asyncio.wait({done, immortal},
+                               return_when=asyncio.FIRST_COMPLETED)
+            self.assertFalse(immortal._asyncio_awaited_by)
+            immortal.cancel()
+
+        self.loop.run_until_complete(self.new_task(self.loop, coro()))
+
     def test_wait_really_done(self):
         # there is possibility that some tasks in the pending list
         # became done but their callbacks haven't all been called yet
diff --git a/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst b/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst
new file mode 100644 (file)
index 0000000..fb7e32a
--- /dev/null
@@ -0,0 +1,3 @@
+Fix :func:`asyncio.wait` leaking waiting tasks via the await-graph when racing a
+future that never resolves. The waiting task is now discarded from every future's
+``awaited_by`` set once :func:`~asyncio.wait` returns, even for pending futures.