diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 5dbe4b28d236d3..d7d64162108d5c 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -2052,7 +2052,9 @@ def get_debug(self): return self._debug def set_debug(self, enabled): - self._debug = enabled + # Storing a non-boolean 'debug' flag causes a crash upon finalization. + # See: https://github.com/python/cpython/issues/126881. + self._debug = enabled = bool(enabled) if self.is_running(): self.call_soon_threadsafe(self._set_coroutine_origin_tracking, enabled) diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index c14a0bb180d79b..3e91cdd42c9e19 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -6,6 +6,7 @@ import platform import socket import sys +import textwrap import threading import time import unittest @@ -393,6 +394,37 @@ def test_set_debug(self): self.loop.set_debug(False) self.assertFalse(self.loop.get_debug()) + def test_set_debug_non_boolean(self): + # Assert that set_debug with a non-boolean value does not crash. + # + # In order to check that the crash does not happen anymore, we + # deliberately leave the loop unclosed. Note that the loop will + # be closed automatically when calling __del__() but a warning + # will be emitted. + # + # See: https://github.com/python/cpython/issues/126881. + code = textwrap.dedent(""" + from asyncio.base_events import BaseEventLoop + loop = BaseEventLoop() + loop.set_debug(0.0005) + loop._run_forever_setup() + loop.__del__() + """) + _, stdout, stderr = assert_python_ok('-c', code) + self.assertEqual(stdout, b'') + self.assertIn(b'ResourceWarning: unclosed event loop', stderr) + + code = textwrap.dedent(""" + from asyncio.base_events import BaseEventLoop + loop = BaseEventLoop() + loop.set_debug([]) + loop._run_forever_setup() + loop.__del__() + """) + _, stdout, stderr = assert_python_ok('-c', code) + self.assertEqual(stdout, b'') + self.assertIn(b'ResourceWarning: unclosed event loop', stderr) + def test__run_once_schedule_handle(self): handle = None processed = False diff --git a/Misc/NEWS.d/next/Library/2024-11-16-10-44-58.gh-issue-126881.W4TXxX.rst b/Misc/NEWS.d/next/Library/2024-11-16-10-44-58.gh-issue-126881.W4TXxX.rst new file mode 100644 index 00000000000000..22a9cfe352f278 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-11-16-10-44-58.gh-issue-126881.W4TXxX.rst @@ -0,0 +1,2 @@ +Fix a crash upon finalization when passing a non-boolean value to +:meth:`loop.set_debug `. Patch by Bénédikt Tran.