From 16b93b3d0e2bf8dc22d11e8625af6d9cc913ec88 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 13 Jun 2002 21:32:51 +0000 Subject: Fix for SF bug 532646. This is a little simpler than what Neal suggested there, based upon a better analysis (__getattr__ is a red herring). Will backport to 2.2. --- Lib/test/test_class.py | 14 ++++++++++++++ Objects/classobject.c | 18 +++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 151074e..5240b3a 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -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?" diff --git a/Objects/classobject.c b/Objects/classobject.c index 4522097..8091f0f 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -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; } -- cgit v0.12