Skip to content

bpo-38785: Prevent asyncio from crashing #17144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Lib/asyncio/futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ def _log_traceback(self, val):

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.
Expand Down
39 changes: 39 additions & 0 deletions Lib/test/test_asyncio/test_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,5 +822,44 @@ def _new_future(self):
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()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Prevent asyncio from crashing if parent ``__init__`` is not called from a
constructor of object derived from ``asyncio.Future``.
1 change: 1 addition & 0 deletions Modules/_asynciomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down