]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-126083: Fix a reference leak in `asyncio.Task` when reinitializing with new non...
authorNico-Posada <102486290+Nico-Posada@users.noreply.github.com>
Thu, 31 Oct 2024 07:47:57 +0000 (03:47 -0400)
committerGitHub <noreply@github.com>
Thu, 31 Oct 2024 07:47:57 +0000 (10:47 +0300)
Lib/test/test_asyncio/test_tasks.py
Misc/NEWS.d/next/Library/2024-10-28-22-35-22.gh-issue-126083.TuI--n.rst [new file with mode: 0644]
Modules/_asynciomodule.c

index a1013ab803348de0097326fd9e133552676d6d5e..9d2d356631b42c5e3c7e03338757e5bf528efdd9 100644 (file)
@@ -2688,6 +2688,28 @@ class BaseTaskTests:
         finally:
             loop.close()
 
+    def test_proper_refcounts(self):
+        # see: https://github.com/python/cpython/issues/126083
+        class Break:
+            def __str__(self):
+                raise RuntimeError("break")
+
+        obj = object()
+        initial_refcount = sys.getrefcount(obj)
+
+        coro = coroutine_function()
+        loop = asyncio.new_event_loop()
+        task = asyncio.Task.__new__(asyncio.Task)
+
+        for _ in range(5):
+            with self.assertRaisesRegex(RuntimeError, 'break'):
+                task.__init__(coro, loop=loop, context=obj, name=Break())
+
+        coro.close()
+        del task
+
+        self.assertEqual(sys.getrefcount(obj), initial_refcount)
+
 
 def add_subclass_tests(cls):
     BaseTask = cls.Task
diff --git a/Misc/NEWS.d/next/Library/2024-10-28-22-35-22.gh-issue-126083.TuI--n.rst b/Misc/NEWS.d/next/Library/2024-10-28-22-35-22.gh-issue-126083.TuI--n.rst
new file mode 100644 (file)
index 0000000..d64b7dd
--- /dev/null
@@ -0,0 +1 @@
+Fixed a reference leak in :class:`asyncio.Task` objects when reinitializing the same object with a non-``None`` context. Patch by Nico Posada.
index d4135f04e56575b581b6a519c15917e66af0ec1a..c2500fbd692d4d0b34218a56527d9d6cd23ea1c4 100644 (file)
@@ -2120,7 +2120,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
             return -1;
         }
     } else {
-        self->task_context = Py_NewRef(context);
+        Py_XSETREF(self->task_context, Py_NewRef(context));
     }
 
     Py_CLEAR(self->task_fut_waiter);