summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2021-03-29 17:53:14 (GMT)
committerGitHub <noreply@github.com>2021-03-29 17:53:14 (GMT)
commitdae1963cf38f730291126b7dadfda89ffb21cefd (patch)
treecc0e8d374128df5050f84b52612eec4136b08ac6
parent7e38d3309e0a5a7b9e23ef933aef0079c6e317f7 (diff)
downloadcpython-dae1963cf38f730291126b7dadfda89ffb21cefd.zip
cpython-dae1963cf38f730291126b7dadfda89ffb21cefd.tar.gz
cpython-dae1963cf38f730291126b7dadfda89ffb21cefd.tar.bz2
bpo-35930: Raising an exception raised in a "future" instance will create reference cycles (GH-24995) (#25071)
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 (cherry picked from commit 32430aadadf6e012e39167d3c18a24e49fb84874) Co-authored-by: Jesús Cea <jcea@jcea.es> Co-authored-by: Jesús Cea <jcea@jcea.es>
-rw-r--r--Lib/concurrent/futures/_base.py38
-rw-r--r--Misc/NEWS.d/next/Library/2021-03-23-17-18-56.bpo-35930.RZ51pM.rst2
2 files changed, 25 insertions, 15 deletions
diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py
index 6001e3b..fd2b244 100644
--- a/Lib/concurrent/futures/_base.py
+++ b/Lib/concurrent/futures/_base.py
@@ -385,7 +385,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
@@ -425,20 +429,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.
diff --git a/Misc/NEWS.d/next/Library/2021-03-23-17-18-56.bpo-35930.RZ51pM.rst b/Misc/NEWS.d/next/Library/2021-03-23-17-18-56.bpo-35930.RZ51pM.rst
new file mode 100644
index 0000000..71c6012
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-03-23-17-18-56.bpo-35930.RZ51pM.rst
@@ -0,0 +1,2 @@
+Raising an exception raised in a "future" instance will create reference
+cycles.