diff --git a/gunicorn/_compat.py b/gunicorn/_compat.py index 38fefe44ff..e4e6b215e7 100644 --- a/gunicorn/_compat.py +++ b/gunicorn/_compat.py @@ -107,11 +107,8 @@ def _wrap_error(exc, mapping, key): new_err = new_err_cls(*exc.args) # raise a new exception with the original traceback - if hasattr(exc, '__traceback__'): - traceback = exc.__traceback__ - else: - traceback = sys.exc_info()[2] - six.reraise(new_err_cls, new_err, traceback) + six.reraise(new_err_cls, new_err, + exc.__traceback__ if hasattr(exc, '__traceback__') else sys.exc_info()[2]) if PY33: import builtins diff --git a/gunicorn/workers/async.py b/gunicorn/workers/async.py index 4acbf3f982..53da7cac8d 100644 --- a/gunicorn/workers/async.py +++ b/gunicorn/workers/async.py @@ -55,13 +55,11 @@ def handle(self, listener, client, addr): except StopIteration as e: self.log.debug("Closing connection. %s", e) except ssl.SSLError: - exc_info = sys.exc_info() # pass to next try-except level - six.reraise(exc_info[0], exc_info[1], exc_info[2]) + six.reraise(*sys.exc_info()) except EnvironmentError: - exc_info = sys.exc_info() # pass to next try-except level - six.reraise(exc_info[0], exc_info[1], exc_info[2]) + six.reraise(*sys.exc_info()) except Exception as e: self.handle_error(req, client, addr, e) except ssl.SSLError as e: diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py index 9ba8e7568b..9cbe6693e5 100644 --- a/gunicorn/workers/base.py +++ b/gunicorn/workers/base.py @@ -134,11 +134,18 @@ def load_wsgi(self): self.log.exception(e) - exc_type, exc_val, exc_tb = sys.exc_info() - self.reloader.add_extra_file(exc_val.filename) - - tb_string = traceback.format_exc(exc_tb) - self.wsgi = util.make_fail_app(tb_string) + # fix from PR #1228 + # storing the traceback into exc_tb will create a circular reference. + # per https://docs.python.org/2/library/sys.html#sys.exc_info warning, + # delete the traceback after use. + try: + exc_type, exc_val, exc_tb = sys.exc_info() + self.reloader.add_extra_file(exc_val.filename) + + tb_string = traceback.format_exc(exc_tb) + self.wsgi = util.make_fail_app(tb_string) + finally: + del exc_tb def init_signals(self): # reset signaling diff --git a/gunicorn/workers/gthread.py b/gunicorn/workers/gthread.py index 25a7e57b52..d66fe4824d 100644 --- a/gunicorn/workers/gthread.py +++ b/gunicorn/workers/gthread.py @@ -339,9 +339,8 @@ def handle_request(self, req, conn): self.log.debug("Closing connection.") return False except EnvironmentError: - exc_info = sys.exc_info() # pass to next try-except level - six.reraise(exc_info[0], exc_info[1], exc_info[2]) + six.reraise(*sys.exc_info()) except Exception: if resp and resp.headers_sent: # If the requests have already been sent, we should close the diff --git a/gunicorn/workers/sync.py b/gunicorn/workers/sync.py index c59c2e9652..15ac08432f 100644 --- a/gunicorn/workers/sync.py +++ b/gunicorn/workers/sync.py @@ -182,9 +182,8 @@ def handle_request(self, listener, req, client, addr): if hasattr(respiter, "close"): respiter.close() except EnvironmentError: - exc_info = sys.exc_info() # pass to next try-except level - six.reraise(exc_info[0], exc_info[1], exc_info[2]) + six.reraise(*sys.exc_info()) except Exception: if resp and resp.headers_sent: # If the requests have already been sent, we should close the