Skip to content

Commit 614d20f

Browse files
committed
Fix ref leak and add tests
1 parent 85799f1 commit 614d20f

File tree

3 files changed

+22
-1
lines changed

3 files changed

+22
-1
lines changed

Lib/test/test_asyncio/test_tasks.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,6 +2688,25 @@ def test_get_context(self):
26882688
finally:
26892689
loop.close()
26902690

2691+
def test_proper_refcounts(self):
2692+
class Break:
2693+
def __str__(self):
2694+
raise Exception("break")
2695+
2696+
obj = object()
2697+
initial_refcount = sys.getrefcount(obj)
2698+
2699+
coro = coroutine_function()
2700+
task = asyncio.Task.__new__(asyncio.Task)
2701+
2702+
for _ in range(10000):
2703+
try:
2704+
task.__init__(coro, context=obj, name=Break())
2705+
except: pass
2706+
del task
2707+
2708+
self.assertEqual(sys.getrefcount(obj), initial_refcount)
2709+
26912710

26922711
def add_subclass_tests(cls):
26932712
BaseTask = cls.Task
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed a reference leak that would happen in asyncio tasks when you would
2+
reinitialize your task object with a non-None context.

Modules/_asynciomodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2120,7 +2120,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
21202120
return -1;
21212121
}
21222122
} else {
2123-
self->task_context = Py_NewRef(context);
2123+
Py_XSETREF(self->task_context, Py_NewRef(context));
21242124
}
21252125

21262126
Py_CLEAR(self->task_fut_waiter);

0 commit comments

Comments
 (0)