Skip to content

Commit 09a7b3b

Browse files
[3.8] bpo-41909: Enable previously disabled recursion checks. (GH-22536) (GH-22551)
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 9ece9cd)
1 parent 28cd96f commit 09a7b3b

File tree

4 files changed

+12
-4
lines changed

4 files changed

+12
-4
lines changed

Lib/test/test_isinstance.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,16 @@ def __bases__(self):
271271

272272
self.assertEqual(True, issubclass(B(), int))
273273

274+
def test_infinite_recursion_in_bases(self):
275+
class X:
276+
@property
277+
def __bases__(self):
278+
return self.__bases__
279+
280+
self.assertRaises(RecursionError, issubclass, X(), int)
281+
self.assertRaises(RecursionError, issubclass, int, X())
282+
self.assertRaises(RecursionError, isinstance, 1, X())
283+
274284

275285
def blowstack(fxn, arg, compare_to):
276286
# Make sure that calling isinstance with a deeply nested tuple for its
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed stack overflow in :func:`issubclass` and :func:`isinstance` when
2+
getting the ``__bases__`` attribute leads to infinite recursion.

Objects/abstract.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,9 +2316,7 @@ abstract_get_bases(PyObject *cls)
23162316
_Py_IDENTIFIER(__bases__);
23172317
PyObject *bases;
23182318

2319-
Py_ALLOW_RECURSION
23202319
(void)_PyObject_LookupAttrId(cls, &PyId___bases__, &bases);
2321-
Py_END_ALLOW_RECURSION
23222320
if (bases != NULL && !PyTuple_Check(bases)) {
23232321
Py_DECREF(bases);
23242322
return NULL;

Objects/unicodeobject.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15285,9 +15285,7 @@ PyUnicode_InternInPlace(PyObject **p)
1528515285
return;
1528615286
}
1528715287
}
15288-
Py_ALLOW_RECURSION
1528915288
t = PyDict_SetDefault(interned, s, s);
15290-
Py_END_ALLOW_RECURSION
1529115289
if (t == NULL) {
1529215290
PyErr_Clear();
1529315291
return;

0 commit comments

Comments
 (0)