Skip to content

Commit

Permalink
tpool: exception in tpool-ed call leaked memory via backtrace
Browse files Browse the repository at this point in the history
  • Loading branch information
boytm authored and temoto committed Mar 10, 2018
1 parent cc34700 commit 69983c6
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
4 changes: 4 additions & 0 deletions eventlet/tpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ def tworker():
raise
except EXC_CLASSES:
rv = sys.exc_info()
if sys.version_info >= (3, 4):
traceback.clear_frames(rv[1].__traceback__)
if six.PY2:
sys.exc_clear()
# test_leakage_from_tracebacks verifies that the use of
# exc_info does not lead to memory leaks
_rspq.put((e, rv))
Expand Down
43 changes: 43 additions & 0 deletions tests/isolated/tpool_exception_leak.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
__test__ = False

if __name__ == '__main__':
import eventlet
import eventlet.tpool
import gc
import pprint

class RequiredException(Exception):
pass

class A(object):
def ok(self):
return 'ok'

def err(self):
raise RequiredException

a = A()

# case 1 no exception
assert eventlet.tpool.Proxy(a).ok() == 'ok'
# yield to tpool_trampoline(), otherwise e.send(rv) have a reference
eventlet.sleep(0.1)
gc.collect()
refs = gc.get_referrers(a)
assert len(refs) == 1, 'tpool.Proxy-ied object leaked: {}'.format(pprint.pformat(refs))

# case 2 with exception
def test_exception():
try:
eventlet.tpool.Proxy(a).err()
assert False, 'expected exception'
except RequiredException:
pass
test_exception()
# yield to tpool_trampoline(), otherwise e.send(rv) have a reference
eventlet.sleep(0.1)
gc.collect()
refs = gc.get_referrers(a)
assert len(refs) == 1, 'tpool.Proxy-ied object leaked: {}'.format(pprint.pformat(refs))

print('pass')
4 changes: 4 additions & 0 deletions tests/tpool_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,7 @@ def test_leakage_from_tracebacks(self):

def test_isolate_from_socket_default_timeout():
tests.run_isolated('tpool_isolate_socket_default_timeout.py', timeout=1)


def test_exception_leak():
tests.run_isolated('tpool_exception_leak.py')

0 comments on commit 69983c6

Please sign in to comment.