summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_object.h2
-rw-r--r--Modules/_asynciomodule.c19
2 files changed, 15 insertions, 6 deletions
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index d7d68f9..e26cb76 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -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) \
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index b8b184a..48f0ef9 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -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);