diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2014-01-22 12:24:46 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2014-01-22 12:24:46 (GMT) |
commit | 09761e7c9cf984b8164c172fcf9f1a5994402495 (patch) | |
tree | 8abf29a20201a6d00e620daf3376599a3e9d2c1b /Lib/contextlib.py | |
parent | 0e3b0e397e7bd986e2284e2b9ed2be00b404019c (diff) | |
download | cpython-09761e7c9cf984b8164c172fcf9f1a5994402495.zip cpython-09761e7c9cf984b8164c172fcf9f1a5994402495.tar.gz cpython-09761e7c9cf984b8164c172fcf9f1a5994402495.tar.bz2 |
Issue #20317: Don't create a reference loop in ExitStack
Diffstat (limited to 'Lib/contextlib.py')
-rw-r--r-- | Lib/contextlib.py | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/Lib/contextlib.py b/Lib/contextlib.py index f8e026b..f878285 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -231,11 +231,19 @@ class ExitStack(object): # we were actually nesting multiple with statements frame_exc = sys.exc_info()[1] def _fix_exception_context(new_exc, old_exc): + # Context isn't what we want, so find the end of the chain while 1: exc_context = new_exc.__context__ - if exc_context in (None, frame_exc): + if exc_context is old_exc: + # Context is already set correctly (see issue 20317) + return + if exc_context is None or exc_context is frame_exc: break + details = id(new_exc), id(old_exc), id(exc_context) + raise Exception(str(details)) new_exc = exc_context + # Change the end of the chain to point to the exception + # we expect it to reference new_exc.__context__ = old_exc # Callbacks are invoked in LIFO order to match the behaviour of |