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) \
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);