Limit the nesting depth of a tuple passed as the second argument to

isinstance() or issubclass() to the recursion limit of the interpreter.
This commit is contained in:
Brett Cannon 2004-03-20 22:52:14 +00:00
parent c69661725a
commit 4f65331483
3 changed files with 57 additions and 9 deletions

View File

@ -4,6 +4,7 @@
import unittest
from test import test_support
import sys
@ -244,7 +245,23 @@ class TestIsInstanceIsSubclass(unittest.TestCase):
self.assertEqual(True, issubclass(int, (long, (float, int))))
self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring))))
def test_subclass_recursion_limit(self):
# make sure that issubclass raises RuntimeError before the C stack is
# blown
self.assertRaises(RuntimeError, blowstack, issubclass, str, str)
def test_isinstance_recursion_limit(self):
# make sure that issubclass raises RuntimeError before the C stack is
# blown
self.assertRaises(RuntimeError, blowstack, isinstance, '', str)
def blowstack(fxn, arg, compare_to):
# Make sure that calling isinstance with a deeply nested tuple for its
# argument will raise RuntimeError eventually.
tuple_arg = (compare_to,)
for cnt in xrange(sys.getrecursionlimit()+5):
tuple_arg = (tuple_arg,)
fxn(arg, tuple_arg)
def test_main():

View File

@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1?
Core and builtins
-----------------
- Limit the nested depth of a tuple for the second argument to isinstance()
and issubclass() to the recursion limit of the interpreter.
Fixes bug #858016 .
- Optimized dict iterators, creating separate types for each
and having them reveal their length. Also optimized the
methods: keys(), values(), and items().

View File

@ -1992,8 +1992,8 @@ check_class(PyObject *cls, const char *error)
return -1;
}
int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
static int
recursive_isinstance(PyObject *inst, PyObject *cls, int recursion_depth)
{
PyObject *icls;
static PyObject *__class__ = NULL;
@ -2028,14 +2028,20 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
}
}
else if (PyTuple_Check(cls)) {
/* Not a general sequence -- that opens up the road to
recursion and stack overflow. */
int i, n;
if (!recursion_depth) {
PyErr_SetString(PyExc_RuntimeError,
"nest level of tuple too deep");
return NULL;
}
n = PyTuple_GET_SIZE(cls);
for (i = 0; i < n; i++) {
retval = PyObject_IsInstance(
inst, PyTuple_GET_ITEM(cls, i));
retval = recursive_isinstance(
inst,
PyTuple_GET_ITEM(cls, i),
recursion_depth-1);
if (retval != 0)
break;
}
@ -2060,7 +2066,13 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
}
int
PyObject_IsSubclass(PyObject *derived, PyObject *cls)
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
return recursive_isinstance(inst, cls, Py_GetRecursionLimit());
}
static int
recursive_issubclass(PyObject *derived, PyObject *cls, int recursion_depth)
{
int retval;
@ -2072,9 +2084,17 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
if (PyTuple_Check(cls)) {
int i;
int n = PyTuple_GET_SIZE(cls);
if (!recursion_depth) {
PyErr_SetString(PyExc_RuntimeError,
"nest level of tuple too deep");
return NULL;
}
for (i = 0; i < n; ++i) {
retval = PyObject_IsSubclass(
derived, PyTuple_GET_ITEM(cls, i));
retval = recursive_issubclass(
derived,
PyTuple_GET_ITEM(cls, i),
recursion_depth-1);
if (retval != 0) {
/* either found it, or got an error */
return retval;
@ -2100,6 +2120,13 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
return retval;
}
int
PyObject_IsSubclass(PyObject *derived, PyObject *cls)
{
return recursive_issubclass(derived, cls, Py_GetRecursionLimit());
}
PyObject *
PyObject_GetIter(PyObject *o)
{