summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_asyncio
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2020-05-22 20:33:27 (GMT)
committerGitHub <noreply@github.com>2020-05-22 20:33:27 (GMT)
commit7c30d12bd5359b0f66c4fbc98aa055398bcc8a7e (patch)
tree2719af29b9bd410f1ed7f70b1ab1d3c9357713e0 /Lib/test/test_asyncio
parent909b5714e1303357868bc5e281c1cf508d5d5a17 (diff)
downloadcpython-7c30d12bd5359b0f66c4fbc98aa055398bcc8a7e.zip
cpython-7c30d12bd5359b0f66c4fbc98aa055398bcc8a7e.tar.gz
cpython-7c30d12bd5359b0f66c4fbc98aa055398bcc8a7e.tar.bz2
bpo-40696: Fix a hang that can arise after gen.throw() (GH-20287)
This updates _PyErr_ChainStackItem() to use _PyErr_SetObject() instead of _PyErr_ChainExceptions(). This prevents a hang in certain circumstances because _PyErr_SetObject() performs checks to prevent cycles in the exception context chain while _PyErr_ChainExceptions() doesn't.
Diffstat (limited to 'Lib/test/test_asyncio')
-rw-r--r--Lib/test/test_asyncio/test_tasks.py39
1 files changed, 36 insertions, 3 deletions
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index 63968e2..3734013 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -536,9 +536,42 @@ class BaseTaskTests:
self.assertEqual((type(chained), chained.args),
(KeyError, (3,)))
- task = self.new_task(loop, run())
- loop.run_until_complete(task)
- loop.close()
+ try:
+ task = self.new_task(loop, run())
+ loop.run_until_complete(task)
+ finally:
+ loop.close()
+
+ def test_exception_chaining_after_await_with_context_cycle(self):
+ # Check trying to create an exception context cycle:
+ # https://bugs.python.org/issue40696
+ has_cycle = None
+ loop = asyncio.new_event_loop()
+ self.set_event_loop(loop)
+
+ async def process_exc(exc):
+ raise exc
+
+ async def run():
+ nonlocal has_cycle
+ try:
+ raise KeyError('a')
+ except Exception as exc:
+ task = self.new_task(loop, process_exc(exc))
+ try:
+ await task
+ except BaseException as exc:
+ has_cycle = (exc is exc.__context__)
+ # Prevent a hang if has_cycle is True.
+ exc.__context__ = None
+
+ try:
+ task = self.new_task(loop, run())
+ loop.run_until_complete(task)
+ finally:
+ loop.close()
+ # This also distinguishes from the initial has_cycle=None.
+ self.assertEqual(has_cycle, False)
def test_cancel(self):