bpo-34441: Fix ABC.__subclasscheck__ crash on classes with invalid __subclasses__ (GH-8835)

The missing NULL check was reported by Svace static analyzer.
This commit is contained in:
Alexey Izbyshev 2018-08-20 23:04:19 +03:00 committed by Berker Peksag
parent 4c8555773a
commit cdbf50cba1
3 changed files with 36 additions and 0 deletions

View File

@ -410,6 +410,36 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
issubclass(C(), A) 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): def test_all_new_methods_are_called(self):
class A(metaclass=abc_ABCMeta): class A(metaclass=abc_ABCMeta):
pass pass

View File

@ -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.

View File

@ -665,6 +665,9 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self,
/* 6. Check if it's a subclass of a subclass (recursive). */ /* 6. Check if it's a subclass of a subclass (recursive). */
subclasses = PyObject_CallMethod(self, "__subclasses__", NULL); subclasses = PyObject_CallMethod(self, "__subclasses__", NULL);
if (subclasses == NULL) {
goto end;
}
if (!PyList_Check(subclasses)) { if (!PyList_Check(subclasses)) {
PyErr_SetString(PyExc_TypeError, "__subclasses__() must return a list"); PyErr_SetString(PyExc_TypeError, "__subclasses__() must return a list");
goto end; goto end;