Skip to content

Commit

Permalink
Fix a memory leak related to contextvars support. (#192)
Browse files Browse the repository at this point in the history
Initial patch and memleak discovery by Victor K. @hellysmile.

Fixes #191.
  • Loading branch information
1st1 committed Aug 7, 2018
1 parent 2690ff6 commit 2ddb480
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
24 changes: 24 additions & 0 deletions tests/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import random
import sys
import unittest
import weakref

from uvloop import _testbase as tb

Expand Down Expand Up @@ -117,6 +118,29 @@ async def main():

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):

Expand Down
18 changes: 16 additions & 2 deletions uvloop/cbhandles.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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+')

0 comments on commit 2ddb480

Please sign in to comment.