diff options
author | Yury Selivanov <yury@magic.io> | 2017-12-25 21:16:10 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-25 21:16:10 (GMT) |
commit | e0aef4f3cd339a405d2a7fbd35a50afa64834f84 (patch) | |
tree | 3d141ffc779ca6159b2e193d95ef6e76509612ae | |
parent | 3070b71e5eedf62e49b8e7dedab75742a5f67ece (diff) | |
download | cpython-e0aef4f3cd339a405d2a7fbd35a50afa64834f84.zip cpython-e0aef4f3cd339a405d2a7fbd35a50afa64834f84.tar.gz cpython-e0aef4f3cd339a405d2a7fbd35a50afa64834f84.tar.bz2 |
bpo-31721: Allow Future._log_traceback to only be set to False (#5009)
-rw-r--r-- | Lib/asyncio/futures.py | 22 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_futures.py | 5 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_tasks.py | 9 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2017-12-25-11-09-46.bpo-31721.5gM972.rst | 2 | ||||
-rw-r--r-- | Modules/_asynciomodule.c | 5 |
5 files changed, 37 insertions, 6 deletions
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 13fb47c..1c05b22 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -65,7 +65,7 @@ class Future: # `yield Future()` (incorrect). _asyncio_future_blocking = False - _log_traceback = False + __log_traceback = False def __init__(self, *, loop=None): """Initialize the future. @@ -90,7 +90,7 @@ class Future: ' '.join(self._repr_info())) def __del__(self): - if not self._log_traceback: + if not self.__log_traceback: # set_exception() was not called, or result() or exception() # has consumed the exception return @@ -105,6 +105,16 @@ class Future: context['source_traceback'] = self._source_traceback self._loop.call_exception_handler(context) + @property + def _log_traceback(self): + return self.__log_traceback + + @_log_traceback.setter + def _log_traceback(self, val): + if bool(val): + raise ValueError('_log_traceback can only be set to False') + self.__log_traceback = False + def get_loop(self): """Return the event loop the Future is bound to.""" return self._loop @@ -116,7 +126,7 @@ class Future: change the future's state to cancelled, schedule the callbacks and return True. """ - self._log_traceback = False + self.__log_traceback = False if self._state != _PENDING: return False self._state = _CANCELLED @@ -162,7 +172,7 @@ class Future: raise CancelledError if self._state != _FINISHED: raise InvalidStateError('Result is not ready.') - self._log_traceback = False + self.__log_traceback = False if self._exception is not None: raise self._exception return self._result @@ -179,7 +189,7 @@ class Future: raise CancelledError if self._state != _FINISHED: raise InvalidStateError('Exception is not set.') - self._log_traceback = False + self.__log_traceback = False return self._exception def add_done_callback(self, fn): @@ -237,7 +247,7 @@ class Future: self._exception = exception self._state = _FINISHED self._schedule_callbacks() - self._log_traceback = True + self.__log_traceback = True def __await__(self): if not self.done(): diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index d339616..ab45ee3 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -374,6 +374,11 @@ class BaseFutureTests: test() fut.cancel() + def test_log_traceback(self): + fut = self._new_future(loop=self.loop) + with self.assertRaisesRegex(ValueError, 'can only be set to False'): + fut._log_traceback = True + @mock.patch('asyncio.base_events.logger') def test_tb_logger_abandoned(self, m_log): fut = self._new_future(loop=self.loop) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 0dc6c32..26e4f64 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -623,6 +623,15 @@ class BaseTaskTests: t.cancel() self.assertRaises(asyncio.CancelledError, loop.run_until_complete, t) + def test_log_traceback(self): + async def coro(): + pass + + task = self.new_task(self.loop, coro()) + with self.assertRaisesRegex(ValueError, 'can only be set to False'): + task._log_traceback = True + self.loop.run_until_complete(task) + def test_wait_for_timeout_less_then_0_or_0_future_done(self): def gen(): when = yield diff --git a/Misc/NEWS.d/next/Library/2017-12-25-11-09-46.bpo-31721.5gM972.rst b/Misc/NEWS.d/next/Library/2017-12-25-11-09-46.bpo-31721.5gM972.rst new file mode 100644 index 0000000..a989a94 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-12-25-11-09-46.bpo-31721.5gM972.rst @@ -0,0 +1,2 @@ +Prevent Python crash from happening when Future._log_traceback is set to +True manually. Now it can only be set to False, or a ValueError is raised. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index f8165ab..5ec4ad1 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1058,6 +1058,11 @@ FutureObj_set_log_traceback(FutureObj *fut, PyObject *val) if (is_true < 0) { return -1; } + if (is_true) { + PyErr_SetString(PyExc_ValueError, + "_log_traceback can only be set to False"); + return -1; + } fut->fut_log_tb = is_true; return 0; } |