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

* Use Py_EnterRecursiveCall() in issubclass()

Reviewed-by: Gregory P. Smith <greg@krypto.org> [Google]
(cherry picked from commit 423fa1c181)

Co-authored-by: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2021-10-22 14:46:56 -07:00 committed by GitHub
parent 19903085c3
commit f812fef2f8
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, 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):
# 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);
continue;
}
for (i = 0; i < n; i++) {
r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls);
if (r != 0)
break;
}
Py_DECREF(bases);
return r;
break;
}
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