summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Cannon <bcannon@gmail.com>2004-03-20 22:52:14 (GMT)
committerBrett Cannon <bcannon@gmail.com>2004-03-20 22:52:14 (GMT)
commit4f65331483197a9909b19694688c55fdf9ca7a37 (patch)
tree1d8dae183e1f6528ca75c85082c4eeb8a4e8a803
parentc69661725a9d505d8f33a4a220d5489cb1de750f (diff)
downloadcpython-4f65331483197a9909b19694688c55fdf9ca7a37.zip
cpython-4f65331483197a9909b19694688c55fdf9ca7a37.tar.gz
cpython-4f65331483197a9909b19694688c55fdf9ca7a37.tar.bz2
Limit the nesting depth of a tuple passed as the second argument to
isinstance() or issubclass() to the recursion limit of the interpreter.
-rw-r--r--Lib/test/test_isinstance.py19
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/abstract.c45
3 files changed, 58 insertions, 10 deletions
diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py
index 1b8c593..4562114 100644
--- a/Lib/test/test_isinstance.py
+++ b/Lib/test/test_isinstance.py
@@ -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():
diff --git a/Misc/NEWS b/Misc/NEWS
index b0693e0..9f27fd7 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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().
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 060abc5..3d6d829 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -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)
{