]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-128002: fix `asyncio.all_tasks` against concurrent deallocations of tasks (#128541)
authorKumar Aditya <kumaraditya@python.org>
Thu, 9 Jan 2025 15:56:00 +0000 (21:26 +0530)
committerGitHub <noreply@github.com>
Thu, 9 Jan 2025 15:56:00 +0000 (21:26 +0530)
Include/internal/pycore_object.h
Modules/_asynciomodule.c

index d7d68f938a9f0aa67c66d0c87d9fdd1bcabb790b..e26cb7673f939c6360da6bdfb3ae7271757c9848 100644 (file)
@@ -120,7 +120,7 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
 PyAPI_DATA(Py_ssize_t) _Py_RefTotal;
 
 extern void _Py_AddRefTotal(PyThreadState *, Py_ssize_t);
-extern void _Py_IncRefTotal(PyThreadState *);
+extern PyAPI_FUNC(void) _Py_IncRefTotal(PyThreadState *);
 extern void _Py_DecRefTotal(PyThreadState *);
 
 #  define _Py_DEC_REFTOTAL(interp) \
index b8b184af04a7cb017e77ae328fdcf303d6f646ae..48f0ef95934fa40d1c1bc45f630ac150a32f1e43 100644 (file)
@@ -3772,11 +3772,20 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
 
     llist_for_each_safe(node, &state->asyncio_tasks_head) {
         TaskObj *task = llist_data(node, TaskObj, task_node);
-        if (PyList_Append(tasks, (PyObject *)task) < 0) {
-            Py_DECREF(tasks);
-            Py_DECREF(loop);
-            err = 1;
-            break;
+        // The linked list holds borrowed references to task
+        // as such it is possible that the task is concurrently
+        // deallocated while added to this list.
+        // To protect against concurrent deallocations,
+        // we first try to incref the task which would fail
+        // if it is concurrently getting deallocated in another thread,
+        // otherwise it gets added to the list.
+        if (_Py_TryIncref((PyObject *)task)) {
+            if (_PyList_AppendTakeRef((PyListObject *)tasks, (PyObject *)task) < 0) {
+                Py_DECREF(tasks);
+                Py_DECREF(loop);
+                err = 1;
+                break;
+            }
         }
     }
     ASYNCIO_STATE_UNLOCK(state);