diff options
author | INADA Naoki <methane@users.noreply.github.com> | 2018-03-07 07:27:01 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-07 07:27:01 (GMT) |
commit | fc7df0e664198cb05cafd972f190a18ca422989c (patch) | |
tree | 960e82951c176ac63b1e8891422c013090af5a83 | |
parent | bc3f2289b9007396bfb7f986bee477b6176c1822 (diff) | |
download | cpython-fc7df0e664198cb05cafd972f190a18ca422989c.zip cpython-fc7df0e664198cb05cafd972f190a18ca422989c.tar.gz cpython-fc7df0e664198cb05cafd972f190a18ca422989c.tar.bz2 |
bpo-32999: Fix ABC.__subclasscheck__ crash (GH-6002)
-rw-r--r-- | Lib/test/test_abc.py | 18 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2018-03-06-20-30-20.bpo-32999.lgFXWl.rst | 2 | ||||
-rw-r--r-- | Modules/_abc.c | 37 |
3 files changed, 45 insertions, 12 deletions
diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index af26c1d..6fc3c95 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -392,6 +392,24 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): self.assertIsInstance(42, A) self.assertIsInstance(42, (A,)) + def test_issubclass_bad_arguments(self): + class A(metaclass=abc_ABCMeta): + pass + + with self.assertRaises(TypeError): + issubclass({}, A) # unhashable + + with self.assertRaises(TypeError): + issubclass(42, A) # No __mro__ + + # Python version supports any iterable as __mro__. + # But it's implementation detail and don't emulate it in C version. + class C: + __mro__ = 42 # __mro__ is not tuple + + with self.assertRaises(TypeError): + issubclass(C(), A) + def test_all_new_methods_are_called(self): class A(metaclass=abc_ABCMeta): pass diff --git a/Misc/NEWS.d/next/Library/2018-03-06-20-30-20.bpo-32999.lgFXWl.rst b/Misc/NEWS.d/next/Library/2018-03-06-20-30-20.bpo-32999.lgFXWl.rst new file mode 100644 index 0000000..45e75f9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-03-06-20-30-20.bpo-32999.lgFXWl.rst @@ -0,0 +1,2 @@ +Fix C implemetation of ``ABC.__subclasscheck__(cls, subclass)`` crashed when +``subclass`` is not a type object. diff --git a/Modules/_abc.c b/Modules/_abc.c index 504e23d..8628839 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -16,6 +16,7 @@ _Py_IDENTIFIER(__abstractmethods__); _Py_IDENTIFIER(__class__); _Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__bases__); +_Py_IDENTIFIER(__mro__); _Py_IDENTIFIER(_abc_impl); _Py_IDENTIFIER(__subclasscheck__); _Py_IDENTIFIER(__subclasshook__); @@ -568,7 +569,7 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, PyObject *subclass) /*[clinic end generated code: output=b56c9e4a530e3894 input=1d947243409d10b8]*/ { - PyObject *ok, *mro, *subclasses = NULL, *result = NULL; + PyObject *ok, *mro = NULL, *subclasses = NULL, *result = NULL; Py_ssize_t pos; int incache; _abc_data *impl = _get_impl(self); @@ -637,20 +638,31 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, } Py_DECREF(ok); - /* 4. Check if it's a direct subclass. */ - mro = ((PyTypeObject *)subclass)->tp_mro; - assert(PyTuple_Check(mro)); - for (pos = 0; pos < PyTuple_GET_SIZE(mro); pos++) { - PyObject *mro_item = PyTuple_GET_ITEM(mro, pos); - if (mro_item == NULL) { + /* 4. Check if it's a direct subclass. + * + * if cls in getattr(subclass, '__mro__', ()): + * cls._abc_cache.add(subclass) + * return True + */ + if (_PyObject_LookupAttrId(subclass, &PyId___mro__, &mro) < 0) { + goto end; + } + if (mro != NULL) { + if (!PyTuple_Check(mro)) { + // Python version supports non-tuple iterable. Keep it as + // implementation detail. + PyErr_SetString(PyExc_TypeError, "__mro__ is not a tuple"); goto end; } - if ((PyObject *)self == mro_item) { - if (_add_to_weak_set(&impl->_abc_cache, subclass) < 0) { + for (pos = 0; pos < PyTuple_GET_SIZE(mro); pos++) { + PyObject *mro_item = PyTuple_GET_ITEM(mro, pos); + if ((PyObject *)self == mro_item) { + if (_add_to_weak_set(&impl->_abc_cache, subclass) < 0) { + goto end; + } + result = Py_True; goto end; } - result = Py_True; - goto end; } } @@ -690,7 +702,8 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, result = Py_False; end: - Py_XDECREF(impl); + Py_DECREF(impl); + Py_XDECREF(mro); Py_XDECREF(subclasses); Py_XINCREF(result); return result; |