]> granicus.if.org Git - python/commitdiff
Fix for SF bug 532646. This is a little simpler than what Neal
authorGuido van Rossum <guido@python.org>
Thu, 13 Jun 2002 21:32:51 +0000 (21:32 +0000)
committerGuido van Rossum <guido@python.org>
Thu, 13 Jun 2002 21:32:51 +0000 (21:32 +0000)
suggested there, based upon a better analysis (__getattr__ is a red
herring).  Will backport to 2.2.

Lib/test/test_class.py
Objects/classobject.c

index 151074ecd1c5b8d56e9c9195b740dee65c2147f5..5240b3adfc51ca2c88efd8a8ab362e0d5da1acce 100644 (file)
@@ -274,3 +274,17 @@ class C2:
 try: hash(C2())
 except TypeError: pass
 else: raise TestFailed, "hash(C2()) should raise an exception"
+
+
+# Test for SF bug 532646
+
+class A:
+    pass
+A.__call__ = A()
+a = A()
+try:
+    a() # This should not segfault
+except RuntimeError:
+    pass
+else:
+    raise TestFailed, "how could this not have overflowed the stack?"
index 4522097ac84ddeae05a5c019fff3b485cbf03356..8091f0fbd7ee6978045dcbe7e0882ea1bea9c983 100644 (file)
@@ -1879,6 +1879,7 @@ instance_iternext(PyInstanceObject *self)
 static PyObject *
 instance_call(PyObject *func, PyObject *arg, PyObject *kw)
 {
+       PyThreadState *tstate = PyThreadState_GET();
        PyObject *res, *call = PyObject_GetAttrString(func, "__call__");
        if (call == NULL) {
                PyInstanceObject *inst = (PyInstanceObject*) func;
@@ -1888,7 +1889,22 @@ instance_call(PyObject *func, PyObject *arg, PyObject *kw)
                             PyString_AsString(inst->in_class->cl_name));
                return NULL;
        }
-       res = PyObject_Call(call, arg, kw);
+       /* We must check and increment the recursion depth here. Scenario:
+              class A:
+                  pass
+              A.__call__ = A() # that's right
+              a = A() # ok
+              a() # infinite recursion
+          This bounces between instance_call() and PyObject_Call() without
+          ever hitting eval_frame() (which has the main recursion check). */
+       if (tstate->recursion_depth++ > Py_GetRecursionLimit()) {
+               PyErr_SetString(PyExc_RuntimeError,
+                               "maximum __call__ recursion depth exceeded");
+               res = NULL;
+       }
+       else
+               res = PyObject_Call(call, arg, kw);
+       tstate->recursion_depth--;
        Py_DECREF(call);
        return res;
 }