From 3ed66c2ca0f66c91ebd9ef1cabd6d66b730ee788 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Thu, 11 Dec 2025 14:25:55 +0530 Subject: [PATCH 1/2] fix crash --- Lib/test/test_asyncio/test_tasks.py | 23 +++++++++++++++++++++++ Modules/_asynciomodule.c | 14 +++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 9809621a324450..a3c5351fed0252 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -3045,6 +3045,26 @@ class BaseTaskIntrospectionTests: _enter_task = None _leave_task = None all_tasks = None + Task = None + + def test_register_task_resurrection(self): + register_task = self._register_task + class EvilLoop: + def get_debug(self): + return False + + def call_exception_handler(self, context): + register_task(context["task"]) + + async def coro_fn (): + pass + + coro = coro_fn() + self.addCleanup(coro.close) + loop = EvilLoop() + with self.assertRaises(AttributeError): + self.Task(coro, loop=loop) + def test__register_task_1(self): class TaskLike: @@ -3175,6 +3195,7 @@ class PyIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests): _leave_task = staticmethod(tasks._py_leave_task) all_tasks = staticmethod(tasks._py_all_tasks) current_task = staticmethod(tasks._py_current_task) + Task = tasks._PyTask @unittest.skipUnless(hasattr(tasks, '_c_register_task'), @@ -3187,10 +3208,12 @@ class CIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests): _leave_task = staticmethod(tasks._c_leave_task) all_tasks = staticmethod(tasks._c_all_tasks) current_task = staticmethod(tasks._c_current_task) + Task = tasks._CTask else: _register_task = _unregister_task = _enter_task = _leave_task = None + class BaseCurrentLoopTests: current_task = None diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 9b2b7011244d77..0e6a1e93e04f33 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2990,16 +2990,12 @@ static PyType_Spec Task_spec = { static void TaskObj_dealloc(PyObject *self) { - _PyObject_ResurrectStart(self); - // Unregister the task here so that even if any subclass of Task - // which doesn't end up calling TaskObj_finalize not crashes. - unregister_task((TaskObj *)self); - - PyObject_CallFinalizer(self); - - if (_PyObject_ResurrectEnd(self)) { - return; + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + return; // resurrected } + // unregister the task after finalization so that + // if the task gets resurrected, it remains registered + unregister_task((TaskObj *)self); PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); From af73a7f5726fe8234bd376ccc64168c59327a22f Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:03:17 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-12-11-09-03-07.gh-issue-142556.RuiBte.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-11-09-03-07.gh-issue-142556.RuiBte.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-11-09-03-07.gh-issue-142556.RuiBte.rst b/Misc/NEWS.d/next/Library/2025-12-11-09-03-07.gh-issue-142556.RuiBte.rst new file mode 100644 index 00000000000000..782e62b65a36f3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-11-09-03-07.gh-issue-142556.RuiBte.rst @@ -0,0 +1 @@ +Fix crash when a task gets re-registered during finalization in :mod:`asyncio`. Patch by Kumar Aditya.