Skip to content

Commit 9ece9cd

Browse files
bpo-41909: Enable previously disabled recursion checks. (pythonGH-22536)
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.
1 parent 619f980 commit 9ece9cd

File tree

4 files changed

+12
-4
lines changed

4 files changed

+12
-4
lines changed

Lib/test/test_isinstance.py

+10
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,16 @@ def __bases__(self):
303303

304304
self.assertEqual(True, issubclass(B(), int))
305305

306+
def test_infinite_recursion_in_bases(self):
307+
class X:
308+
@property
309+
def __bases__(self):
310+
return self.__bases__
311+
312+
self.assertRaises(RecursionError, issubclass, X(), int)
313+
self.assertRaises(RecursionError, issubclass, int, X())
314+
self.assertRaises(RecursionError, isinstance, 1, X())
315+
306316

307317
def blowstack(fxn, arg, compare_to):
308318
# Make sure that calling isinstance with a deeply nested tuple for its
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

-2
Original file line numberDiff line numberDiff line change
@@ -2336,9 +2336,7 @@ abstract_get_bases(PyObject *cls)
23362336
_Py_IDENTIFIER(__bases__);
23372337
PyObject *bases;
23382338

2339-
Py_ALLOW_RECURSION
23402339
(void)_PyObject_LookupAttrId(cls, &PyId___bases__, &bases);
2341-
Py_END_ALLOW_RECURSION
23422340
if (bases != NULL && !PyTuple_Check(bases)) {
23432341
Py_DECREF(bases);
23442342
return NULL;

Objects/unicodeobject.c

-2
Original file line numberDiff line numberDiff line change
@@ -15734,9 +15734,7 @@ PyUnicode_InternInPlace(PyObject **p)
1573415734
}
1573515735

1573615736
PyObject *t;
15737-
Py_ALLOW_RECURSION
1573815737
t = PyDict_SetDefault(interned, s, s);
15739-
Py_END_ALLOW_RECURSION
1574015738

1574115739
if (t == NULL) {
1574215740
PyErr_Clear();

0 commit comments

Comments
 (0)