summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse <boycht@gmail.com>2018-03-06 21:29:14 +0800
committerSergey Shepelev <temotor@gmail.com>2018-03-10 21:46:06 +0300
commit3b720213ff5dbd2372610eff7143ff72d9a03f94 (patch)
treec14126fa259cb6db006d244120d2a67ddca3848f
parent6c6cfc565f743c9de88fd131ec392cfb2162a984 (diff)
downloadeventlet-469-tpool-leak.tar.gz
tpool: exception in tpool-ed call leaked memory via backtrace469-tpool-leak
https://github.com/eventlet/eventlet/issues/469 https://github.com/eventlet/eventlet/pull/470
-rw-r--r--eventlet/tpool.py1
-rw-r--r--tests/isolated/tpool_exception_leak.py43
-rw-r--r--tests/tpool_test.py4
3 files changed, 48 insertions, 0 deletions
diff --git a/eventlet/tpool.py b/eventlet/tpool.py
index 1c2dea0..396f877 100644
--- a/eventlet/tpool.py
+++ b/eventlet/tpool.py
@@ -85,6 +85,7 @@ def tworker():
raise
except EXC_CLASSES:
rv = sys.exc_info()
+ sys.exc_clear()
# test_leakage_from_tracebacks verifies that the use of
# exc_info does not lead to memory leaks
_rspq.put((e, rv))
diff --git a/tests/isolated/tpool_exception_leak.py b/tests/isolated/tpool_exception_leak.py
new file mode 100644
index 0000000..3bbf61d
--- /dev/null
+++ b/tests/isolated/tpool_exception_leak.py
@@ -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')
diff --git a/tests/tpool_test.py b/tests/tpool_test.py
index 78e3437..3748da7 100644
--- a/tests/tpool_test.py
+++ b/tests/tpool_test.py
@@ -367,3 +367,7 @@ class TpoolLongTests(tests.LimitedTestCase):
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')