diff options
| author | Jesse <boycht@gmail.com> | 2018-03-06 21:29:14 +0800 |
|---|---|---|
| committer | Sergey Shepelev <temotor@gmail.com> | 2018-03-10 21:46:06 +0300 |
| commit | 3b720213ff5dbd2372610eff7143ff72d9a03f94 (patch) | |
| tree | c14126fa259cb6db006d244120d2a67ddca3848f | |
| parent | 6c6cfc565f743c9de88fd131ec392cfb2162a984 (diff) | |
| download | eventlet-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.py | 1 | ||||
| -rw-r--r-- | tests/isolated/tpool_exception_leak.py | 43 | ||||
| -rw-r--r-- | tests/tpool_test.py | 4 |
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') |
