diff options
author | Jesús Cea <jcea@jcea.es> | 2021-03-29 17:22:13 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-29 17:22:13 (GMT) |
commit | 32430aadadf6e012e39167d3c18a24e49fb84874 (patch) | |
tree | e820f08d0c3a5081f1eed8b10f5c13769ba46fa1 /Lib/concurrent | |
parent | 7bfd65eba73d013eee8789f2009c09c61c31b800 (diff) | |
download | cpython-32430aadadf6e012e39167d3c18a24e49fb84874.zip cpython-32430aadadf6e012e39167d3c18a24e49fb84874.tar.gz cpython-32430aadadf6e012e39167d3c18a24e49fb84874.tar.bz2 |
bpo-35930: Raising an exception raised in a "future" instance will create reference cycles (#24995)
Before: https://lists.es.python.org/pipermail/general/attachments/20201229/0c14bc58/attachment-0002.png
After: https://lists.es.python.org/pipermail/general/attachments/20201229/0c14bc58/attachment-0003.png
Diffstat (limited to 'Lib/concurrent')
-rw-r--r-- | Lib/concurrent/futures/_base.py | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index 00eb548..6095026 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -386,7 +386,11 @@ class Future(object): def __get_result(self): if self._exception: - raise self._exception + try: + raise self._exception + finally: + # Break a reference cycle with the exception in self._exception + self = None else: return self._result @@ -426,20 +430,24 @@ class Future(object): timeout. Exception: If the call raised then that exception will be raised. """ - with self._condition: - if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: - raise CancelledError() - elif self._state == FINISHED: - return self.__get_result() - - self._condition.wait(timeout) - - if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: - raise CancelledError() - elif self._state == FINISHED: - return self.__get_result() - else: - raise TimeoutError() + try: + with self._condition: + if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: + raise CancelledError() + elif self._state == FINISHED: + return self.__get_result() + + self._condition.wait(timeout) + + if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: + raise CancelledError() + elif self._state == FINISHED: + return self.__get_result() + else: + raise TimeoutError() + finally: + # Break a reference cycle with the exception in self._exception + self = None def exception(self, timeout=None): """Return the exception raised by the call that the future represents. |