bpo-38785: Prevent asyncio from crashing (GH-17144)

if parent `__init__` is not called from a constructor of object derived from `asyncio.Future`



https://bugs.python.org/issue38785
This commit is contained in:
Andrew Svetlov 2019-11-13 23:36:46 +02:00 committed by Miss Islington (bot)
parent 61289d4366
commit dad6be5ffe
4 changed files with 46 additions and 1 deletions

View File

@ -115,7 +115,10 @@ class Future:
def get_loop(self):
"""Return the event loop the Future is bound to."""
return self._loop
loop = self._loop
if loop is None:
raise RuntimeError("Future object is not initialized.")
return loop
def cancel(self):
"""Cancel the future and schedule callbacks.

View File

@ -822,5 +822,44 @@ class PyFutureDoneCallbackTests(BaseFutureDoneCallbackTests,
return futures._PyFuture(loop=self.loop)
class BaseFutureInheritanceTests:
def _get_future_cls(self):
raise NotImplementedError
def setUp(self):
super().setUp()
self.loop = self.new_test_loop()
self.addCleanup(self.loop.close)
def test_inherit_without_calling_super_init(self):
# See https://bugs.python.org/issue38785 for the context
cls = self._get_future_cls()
class MyFut(cls):
def __init__(self, *args, **kwargs):
# don't call super().__init__()
pass
fut = MyFut(loop=self.loop)
with self.assertRaisesRegex(
RuntimeError,
"Future object is not initialized."
):
fut.get_loop()
class PyFutureInheritanceTests(BaseFutureInheritanceTests,
test_utils.TestCase):
def _get_future_cls(self):
return futures._PyFuture
class CFutureInheritanceTests(BaseFutureInheritanceTests,
test_utils.TestCase):
def _get_future_cls(self):
return futures._CFuture
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,2 @@
Prevent asyncio from crashing if parent ``__init__`` is not called from a
constructor of object derived from ``asyncio.Future``.

View File

@ -1091,6 +1091,7 @@ static PyObject *
_asyncio_Future_get_loop_impl(FutureObj *self)
/*[clinic end generated code: output=119b6ea0c9816c3f input=cba48c2136c79d1f]*/
{
ENSURE_FUTURE_ALIVE(self)
Py_INCREF(self->fut_loop);
return self->fut_loop;
}