mirror of https://github.com/python/cpython
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
|
import unittest
|
||||||
from test import test_support
|
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(int, (long, (float, int))))
|
||||||
self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring))))
|
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():
|
def test_main():
|
||||||
|
|
|
@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1?
|
||||||
Core and builtins
|
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
|
- Optimized dict iterators, creating separate types for each
|
||||||
and having them reveal their length. Also optimized the
|
and having them reveal their length. Also optimized the
|
||||||
methods: keys(), values(), and items().
|
methods: keys(), values(), and items().
|
||||||
|
|
|
@ -1992,8 +1992,8 @@ check_class(PyObject *cls, const char *error)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
PyObject_IsInstance(PyObject *inst, PyObject *cls)
|
recursive_isinstance(PyObject *inst, PyObject *cls, int recursion_depth)
|
||||||
{
|
{
|
||||||
PyObject *icls;
|
PyObject *icls;
|
||||||
static PyObject *__class__ = NULL;
|
static PyObject *__class__ = NULL;
|
||||||
|
@ -2028,14 +2028,20 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (PyTuple_Check(cls)) {
|
else if (PyTuple_Check(cls)) {
|
||||||
/* Not a general sequence -- that opens up the road to
|
|
||||||
recursion and stack overflow. */
|
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
|
if (!recursion_depth) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"nest level of tuple too deep");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
n = PyTuple_GET_SIZE(cls);
|
n = PyTuple_GET_SIZE(cls);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
retval = PyObject_IsInstance(
|
retval = recursive_isinstance(
|
||||||
inst, PyTuple_GET_ITEM(cls, i));
|
inst,
|
||||||
|
PyTuple_GET_ITEM(cls, i),
|
||||||
|
recursion_depth-1);
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2060,7 +2066,13 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
int retval;
|
||||||
|
|
||||||
|
@ -2072,9 +2084,17 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
|
||||||
if (PyTuple_Check(cls)) {
|
if (PyTuple_Check(cls)) {
|
||||||
int i;
|
int i;
|
||||||
int n = PyTuple_GET_SIZE(cls);
|
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) {
|
for (i = 0; i < n; ++i) {
|
||||||
retval = PyObject_IsSubclass(
|
retval = recursive_issubclass(
|
||||||
derived, PyTuple_GET_ITEM(cls, i));
|
derived,
|
||||||
|
PyTuple_GET_ITEM(cls, i),
|
||||||
|
recursion_depth-1);
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
/* either found it, or got an error */
|
/* either found it, or got an error */
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -2100,6 +2120,13 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyObject_IsSubclass(PyObject *derived, PyObject *cls)
|
||||||
|
{
|
||||||
|
return recursive_issubclass(derived, cls, Py_GetRecursionLimit());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyObject_GetIter(PyObject *o)
|
PyObject_GetIter(PyObject *o)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue