Fix a memory leak related to contextvars support. (#192)

Initial patch and memleak discovery by Victor K. @hellysmile.

Fixes #191.
This commit is contained in:
Yury Selivanov 2018-08-07 12:56:06 -04:00
parent ea25545f3a
commit aadcd6f47b
2 changed files with 40 additions and 2 deletions

View File

@ -3,6 +3,7 @@ import decimal
import random
import sys
import unittest
import weakref
from uvloop import _testbase as tb
@ -117,6 +118,29 @@ class _ContextBaseTests:
self.assertEqual(cvar.get(), -1)
@unittest.skipUnless(PY37, 'requires Python 3.7')
def test_task_context_4(self):
import contextvars
cvar = contextvars.ContextVar('cvar', default='nope')
class TrackMe:
pass
tracked = TrackMe()
ref = weakref.ref(tracked)
async def sub():
cvar.set(tracked)
self.loop.call_soon(lambda: None)
async def main():
await self.loop.create_task(sub())
task = self.loop.create_task(main())
self.loop.run_until_complete(task)
del tracked
self.assertIsNone(ref())
class Test_UV_Context(_ContextBaseTests, tb.UVTestCase):

View File

@ -15,9 +15,11 @@ cdef class Handle:
self._source_traceback = extract_stack()
cdef inline _set_context(self, object context):
cdef PyContext* current_context
if PY37:
if context is None:
context = <object>PyContext_CopyCurrent()
context = copy_current_context()
self.context = context
else:
if context is not None:
@ -179,7 +181,7 @@ cdef class TimerHandle:
if PY37:
if context is None:
context = <object>PyContext_CopyCurrent()
context = copy_current_context()
self.context = context
else:
if context is not None:
@ -400,3 +402,15 @@ cdef extract_stack():
stack.reverse()
return stack
cdef copy_current_context():
cdef PyContext* current_context
if PY37:
current_context = PyContext_CopyCurrent()
py_context = <object>current_context
Py_XDECREF(<PyObject*>current_context)
return py_context
raise NotImplementedError('"contextvars" support requires Python 3.7+')