diff options
| author | Chris McDonough <chrism@plope.com> | 2011-08-02 08:45:20 -0400 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-08-02 08:45:20 -0400 |
| commit | 6456c2d69727369826b3cc31e168704a402bab89 (patch) | |
| tree | 04702faa812ed7a849c9d1d5ba7d4fce95332c2d | |
| parent | 95a3791409f4a936c47e7018e75f14fc3b701380 (diff) | |
| download | pyramid-6456c2d69727369826b3cc31e168704a402bab89.tar.gz pyramid-6456c2d69727369826b3cc31e168704a402bab89.tar.bz2 pyramid-6456c2d69727369826b3cc31e168704a402bab89.zip | |
avoid memory leak potential when assigning sys.exc_info() result to an attr of the request
| -rw-r--r-- | pyramid/router.py | 9 | ||||
| -rw-r--r-- | pyramid/tests/test_router.py | 13 |
2 files changed, 16 insertions, 6 deletions
diff --git a/pyramid/router.py b/pyramid/router.py index aa9e4a1ba..ddec23cdb 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -168,7 +168,6 @@ class Router(object): # handle exceptions raised during root finding and view-exec except Exception, why: - exc_info = sys.exc_info() # clear old generated request.response, if any; it may # have been mutated by the view, and its state is not # sane (e.g. caching headers) @@ -176,7 +175,7 @@ class Router(object): del attrs['response'] attrs['exception'] = why - attrs['exc_info'] = exc_info + attrs['exc_info'] = sys.exc_info() for_ = (IExceptionViewClassifier, request_iface.combined, @@ -217,8 +216,10 @@ class Router(object): request.registry = registry response = self.handle_request(request) finally: - if request is not None and request.finished_callbacks: - request._process_finished_callbacks() + if request is not None: + if request.finished_callbacks: + request._process_finished_callbacks() + request.exc_info = None # avoid leak return response(request.environ, start_response) finally: diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py index e44465992..b943f1ee6 100644 --- a/pyramid/tests/test_router.py +++ b/pyramid/tests/test_router.py @@ -790,6 +790,7 @@ class TestRouter(unittest.TestCase): from pyramid.interfaces import IRequest from pyramid.interfaces import IViewClassifier from pyramid.interfaces import IRequestFactory + from pyramid.interfaces import IExceptionViewClassifier def rfactory(environ): return request self.registry.registerUtility(rfactory, IRequestFactory) @@ -799,16 +800,24 @@ class TestRouter(unittest.TestCase): directlyProvides(context, IContext) self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() + response.app_iter = ['OK'] view = DummyView(response, raise_exception=RuntimeError) environ = self._makeEnviron() + def exception_view(context, request): + self.assertEqual(request.exc_info[0], RuntimeError) + return response self._registerView(view, '', IViewClassifier, IRequest, IContext) + self._registerView(exception_view, '', IExceptionViewClassifier, + IRequest, RuntimeError) router = self._makeOne() start_response = DummyStartResponse() - self.assertRaises(RuntimeError, router, environ, start_response) + result = router(environ, start_response) + self.assertEqual(result, ['OK']) # ``exception`` must be attached to request even if a suitable # exception view cannot be found self.assertEqual(request.exception.__class__, RuntimeError) - self.assertEqual(request.exc_info[0], RuntimeError) + # we clean up the exc_info after the request + self.assertEqual(request.exc_info, None) def test_call_view_raises_exception_view(self): from pyramid.interfaces import IViewClassifier |
