summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Svetlov <andrew.svetlov@gmail.com>2019-11-13 21:36:46 (GMT)
committerMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-11-13 21:36:46 (GMT)
commitdad6be5ffe48beb74fad78cf758b886afddc7aed (patch)
tree838e3725e0b281904f0ad097e282997570469b1a
parent61289d436661025a3111065482275d49a4850b8d (diff)
downloadcpython-dad6be5ffe48beb74fad78cf758b886afddc7aed.zip
cpython-dad6be5ffe48beb74fad78cf758b886afddc7aed.tar.gz
cpython-dad6be5ffe48beb74fad78cf758b886afddc7aed.tar.bz2
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
-rw-r--r--Lib/asyncio/futures.py5
-rw-r--r--Lib/test/test_asyncio/test_futures.py39
-rw-r--r--Misc/NEWS.d/next/Library/2019-11-13-16-17-43.bpo-38785.NEOEfk.rst2
-rw-r--r--Modules/_asynciomodule.c1
4 files changed, 46 insertions, 1 deletions
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 98a5308e..9afda22 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -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.
diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py
index 2e4583d..ee5edd5 100644
--- a/Lib/test/test_asyncio/test_futures.py
+++ b/Lib/test/test_asyncio/test_futures.py
@@ -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()
diff --git a/Misc/NEWS.d/next/Library/2019-11-13-16-17-43.bpo-38785.NEOEfk.rst b/Misc/NEWS.d/next/Library/2019-11-13-16-17-43.bpo-38785.NEOEfk.rst
new file mode 100644
index 0000000..49e9937
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-11-13-16-17-43.bpo-38785.NEOEfk.rst
@@ -0,0 +1,2 @@
+Prevent asyncio from crashing if parent ``__init__`` is not called from a
+constructor of object derived from ``asyncio.Future``.
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index 89b2fde..5e1bcfb 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -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;
}