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:
parent
c69661725a
commit
4f65331483
|
@ -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():
|
||||
|
|
|
@ -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().
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue