From cdbf50cba1664f72ae6621a89c324a32fea70377 Mon Sep 17 00:00:00 2001 From: Alexey Izbyshev Date: Mon, 20 Aug 2018 23:04:19 +0300 Subject: [PATCH] bpo-34441: Fix ABC.__subclasscheck__ crash on classes with invalid __subclasses__ (GH-8835) The missing NULL check was reported by Svace static analyzer. --- Lib/test/test_abc.py | 30 +++++++++++++++++++ .../2018-08-20-16-48-32.bpo-34441._zx9lU.rst | 3 ++ Modules/_abc.c | 3 ++ 3 files changed, 36 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-08-20-16-48-32.bpo-34441._zx9lU.rst diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index 6fc3c95e4a..9f5afb241a 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 0000000000..6db095bdf0 --- /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 562a2e6d73..ce9140fd03 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; -- 2.49.0