diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2020-10-04 22:27:38 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-04 22:27:38 (GMT) |
commit | 7aa22ba923509af1dbf115c090964f503c84ca8d (patch) | |
tree | 27a570eb3dcdf44352df06ff0dbfb0f6eb694fd8 | |
parent | f3a6b7fc0b46afbe5d4d450b94a9d077e50b15d5 (diff) | |
download | cpython-7aa22ba923509af1dbf115c090964f503c84ca8d.zip cpython-7aa22ba923509af1dbf115c090964f503c84ca8d.tar.gz cpython-7aa22ba923509af1dbf115c090964f503c84ca8d.tar.bz2 |
[3.9] bpo-41909: Enable previously disabled recursion checks. (GH-22536) (GH-22550)
Enable recursion checks which were disabled when get __bases__ of
non-type objects in issubclass() and isinstance() and when intern
strings. It fixes a stack overflow when getting __bases__ leads
to infinite recursion.
Originally recursion checks was disabled for PyDict_GetItem() which
silences all errors including the one raised in case of detected
recursion and can return incorrect result. But now the code uses
PyDict_GetItemWithError() and PyDict_SetDefault() instead.
(cherry picked from commit 9ece9cd65cdeb0a1f6e60475bbd0219161c348ac)
-rw-r--r-- | Lib/test/test_isinstance.py | 10 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst | 2 | ||||
-rw-r--r-- | Objects/abstract.c | 2 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 2 |
4 files changed, 12 insertions, 4 deletions
diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py index 53639e9..31b3899 100644 --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -271,6 +271,16 @@ class TestIsInstanceIsSubclass(unittest.TestCase): self.assertEqual(True, issubclass(B(), int)) + def test_infinite_recursion_in_bases(self): + class X: + @property + def __bases__(self): + return self.__bases__ + + self.assertRaises(RecursionError, issubclass, X(), int) + self.assertRaises(RecursionError, issubclass, int, X()) + self.assertRaises(RecursionError, isinstance, 1, X()) + def blowstack(fxn, arg, compare_to): # Make sure that calling isinstance with a deeply nested tuple for its diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst new file mode 100644 index 0000000..388cfea --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst @@ -0,0 +1,2 @@ +Fixed stack overflow in :func:`issubclass` and :func:`isinstance` when +getting the ``__bases__`` attribute leads to infinite recursion. diff --git a/Objects/abstract.c b/Objects/abstract.c index 1d671c9..1922619 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2375,9 +2375,7 @@ abstract_get_bases(PyObject *cls) _Py_IDENTIFIER(__bases__); PyObject *bases; - Py_ALLOW_RECURSION (void)_PyObject_LookupAttrId(cls, &PyId___bases__, &bases); - Py_END_ALLOW_RECURSION if (bases != NULL && !PyTuple_Check(bases)) { Py_DECREF(bases); return NULL; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4c8c880..3c2383d 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -15602,9 +15602,7 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *t; - Py_ALLOW_RECURSION t = PyDict_SetDefault(interned, s, s); - Py_END_ALLOW_RECURSION if (t == NULL) { PyErr_Clear(); |