bpo-30570: Use Py_EnterRecursiveCall() in issubclass() (GH-29048)

* Use Py_EnterRecursiveCall() in issubclass()

Reviewed-by: Gregory P. Smith <greg@krypto.org> [Google]
This commit is contained in:
Dennis Sweeney 2021-10-22 17:24:08 -04:00 committed by GitHub
parent f6e8b80d20
commit 423fa1c181
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 7 deletions

View File

@ -313,6 +313,36 @@ class TestIsInstanceIsSubclass(unittest.TestCase):
self.assertRaises(RecursionError, issubclass, int, X()) self.assertRaises(RecursionError, issubclass, int, X())
self.assertRaises(RecursionError, isinstance, 1, X()) self.assertRaises(RecursionError, isinstance, 1, X())
def test_infinite_recursion_via_bases_tuple(self):
"""Regression test for bpo-30570."""
class Failure(object):
def __getattr__(self, attr):
return (self, None)
with self.assertRaises(RecursionError):
issubclass(Failure(), int)
def test_infinite_cycle_in_bases(self):
"""Regression test for bpo-30570."""
class X:
@property
def __bases__(self):
return (self, self, self)
self.assertRaises(RecursionError, issubclass, X(), int)
def test_infinitely_many_bases(self):
"""Regression test for bpo-30570."""
class X:
def __getattr__(self, attr):
self.assertEqual(attr, "__bases__")
class A:
pass
class B:
pass
A.__getattr__ = B.__getattr__ = X.__getattr__
return (A(), B())
self.assertRaises(RecursionError, issubclass, X(), int)
def blowstack(fxn, arg, compare_to): def blowstack(fxn, arg, compare_to):
# Make sure that calling isinstance with a deeply nested tuple for its # Make sure that calling isinstance with a deeply nested tuple for its

View File

@ -0,0 +1 @@
Fixed a crash in ``issubclass()`` from infinite recursion when searching pathological ``__bases__`` tuples.

View File

@ -2557,14 +2557,22 @@ abstract_issubclass(PyObject *derived, PyObject *cls)
derived = PyTuple_GET_ITEM(bases, 0); derived = PyTuple_GET_ITEM(bases, 0);
continue; continue;
} }
for (i = 0; i < n; i++) { break;
r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls);
if (r != 0)
break;
}
Py_DECREF(bases);
return r;
} }
assert(n >= 2);
if (Py_EnterRecursiveCall(" in __issubclass__")) {
Py_DECREF(bases);
return -1;
}
for (i = 0; i < n; i++) {
r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls);
if (r != 0) {
break;
}
}
Py_LeaveRecursiveCall();
Py_DECREF(bases);
return r;
} }
static int static int