summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_abc.py30
-rw-r--r--Misc/NEWS.d/next/Library/2018-08-20-16-48-32.bpo-34441._zx9lU.rst3
-rw-r--r--Modules/_abc.c3
3 files changed, 36 insertions, 0 deletions
diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py
index 6fc3c95..9f5afb2 100644
--- a/Lib/test/test_abc.py
+++ b/Lib/test/test_abc.py
@@ -410,6 +410,36 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
with self.assertRaises(TypeError):
issubclass(C(), A)
+ # bpo-34441: Check that issubclass() doesn't crash on bogus
+ # classes.
+ bogus_subclasses = [
+ None,
+ lambda x: [],
+ lambda: 42,
+ lambda: [42],
+ ]
+
+ for i, func in enumerate(bogus_subclasses):
+ class S(metaclass=abc_ABCMeta):
+ __subclasses__ = func
+
+ with self.subTest(i=i):
+ with self.assertRaises(TypeError):
+ issubclass(int, S)
+
+ # Also check that issubclass() propagates exceptions raised by
+ # __subclasses__.
+ exc_msg = "exception from __subclasses__"
+
+ def raise_exc():
+ raise Exception(exc_msg)
+
+ class S(metaclass=abc_ABCMeta):
+ __subclasses__ = raise_exc
+
+ with self.assertRaisesRegex(Exception, exc_msg):
+ issubclass(int, S)
+
def test_all_new_methods_are_called(self):
class A(metaclass=abc_ABCMeta):
pass
diff --git a/Misc/NEWS.d/next/Library/2018-08-20-16-48-32.bpo-34441._zx9lU.rst b/Misc/NEWS.d/next/Library/2018-08-20-16-48-32.bpo-34441._zx9lU.rst
new file mode 100644
index 0000000..6db095b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-08-20-16-48-32.bpo-34441._zx9lU.rst
@@ -0,0 +1,3 @@
+Fix crash when an ``ABC``-derived class with invalid ``__subclasses__`` is
+passed as the second argument to :func:`issubclass()`. Patch by Alexey
+Izbyshev.
diff --git a/Modules/_abc.c b/Modules/_abc.c
index 562a2e6..ce9140f 100644
--- a/Modules/_abc.c
+++ b/Modules/_abc.c
@@ -665,6 +665,9 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self,
/* 6. Check if it's a subclass of a subclass (recursive). */
subclasses = PyObject_CallMethod(self, "__subclasses__", NULL);
+ if (subclasses == NULL) {
+ goto end;
+ }
if (!PyList_Check(subclasses)) {
PyErr_SetString(PyExc_TypeError, "__subclasses__() must return a list");
goto end;