Skip to content

Commit

Permalink
bpo-41909: Enable previously disabled recursion checks. (pythonGH-22536)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
serhiy-storchaka authored Oct 4, 2020
1 parent 619f980 commit 9ece9cd
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 4 deletions.
10 changes: 10 additions & 0 deletions Lib/test/test_isinstance.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,16 @@ def __bases__(self):

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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed stack overflow in :func:`issubclass` and :func:`isinstance` when
getting the ``__bases__`` attribute leads to infinite recursion.
2 changes: 0 additions & 2 deletions Objects/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -2336,9 +2336,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;
Expand Down
2 changes: 0 additions & 2 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -15734,9 +15734,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();
Expand Down

0 comments on commit 9ece9cd

Please sign in to comment.