[Python-bugs-list] [ python-Bugs-483469 ] crash on unbounded recursion in __del__ .
noreply@sourceforge.net
noreply@sourceforge.net
Tue, 27 Nov 2001 15:03:15 -0800
Bugs item #483469, was opened at 2001-11-19 07:49
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=483469&group_id=5470
Category: Python Interpreter Core
Group: Python 2.1.1
Status: Open
Resolution: None
Priority: 4
Submitted By: te (elaias)
>Assigned to: Tim Peters (tim_one)
Summary: crash on unbounded recursion in __del__ .
Initial Comment:
do the following.
>>> class C:
... def __del__(self):
... c = C()
>>> c = C()
>>> d = range(100) #anything really
>>> c = d
>>> c
Segmentation fault (core dumped)
----------------------------------------------------------------------
>Comment By: Tim Peters (tim_one)
Date: 2001-11-27 15:03
Message:
Logged In: YES
user_id=31435
Back to me.
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-11-27 14:37
Message:
Logged In: YES
user_id=31435
OK, Python's recursion check does trigger if "del c" is
included at the end of the __del__ method. However, as-is,
the destruction of c is a side effect of __del__'s frame
getting decref'ed, and the latter happens at the end of
PyEval_EvalCodeEx(). eval_frame() is long gone by then,
and tstate->recursion_depth is checked in the latter.
To be clear, there is a deep chain of Python frames, but
they're all in the process of being destructed, and tstate-
>recursion_depth has already been decremented (it's just 3
at the time this blew up on my Windows box): eval_frame()
is not on the C stack (except for a few times at the base
of the C stack).
So, in this sense, it's a failure of the recursion-depth
hacks to model the true depth of the C stack. Note there
are actually 10 levels of C stack for each Python level
here: PyEval_EvalCodeEx decrefs the frame, which invokes
_Py_Dealloc, then to frame_dealloc, which decrefs c and
triggers _Py_Dealloc -> instance_dealloc, which finds a
__del__ method and so does PyEval_CallObjectWithKeywords ->
PyObject_Call -> instancemethod_call -> PyObject_Call ->
function_call -> PyEval_EvalCodeEx, and we start all over
again.
No bright ideas here, so unassigned again.
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-11-27 13:00
Message:
Logged In: YES
user_id=31435
Assigned to me (to figure out why the Python-level
recursion check isn't triggering, not to tumble into the
bottomless "outguess all C runtimes" pit).
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-11-23 18:17
Message:
Logged In: YES
user_id=6380
Let's be clear about rexec. It is currently a pathetic
excuse for security. It *could* be made safe, and this is
one of the things that would have to be fixed; but there are
so many other places that I don't really care any more
whether this particular core dump gets fixed (at least not
from a security p.o.v.).
It's strange though that even though there's a Python
function at each level, the Python stack limit check doesn't
trigger before C stack overflows. Maybe it would make more
sense to spend some time getting the general stack limit
check more robust. Unfortunately this has to be done
separately for each C compiler and each operating system
variation... :-(
----------------------------------------------------------------------
Comment By: Andrew Bennetts (spiv)
Date: 2001-11-20 06:53
Message:
Logged In: YES
user_id=50945
I agree that segfaults like this are a problem; this is a
potential security problem because it means that untrusted
code can crash the interpreter, even if you try to use
something like rexec.
----------------------------------------------------------------------
Comment By: te (elaias)
Date: 2001-11-19 09:45
Message:
Logged In: YES
user_id=109241
Sorry, I thought that this was obvious enough for the person
responsible that I didn't have to explain. Thanks for the
correction though. And I would say that a segfault in any
program is a problem, especially an interpreter.
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-11-19 09:18
Message:
Logged In: YES
user_id=31435
Well, it's not just "an assignment": the __del__ creates a
local instance of C, which is destroyed while __del__ is
trying to return, which calls __del__ again, which creates
a local instance of C, which is destroyed while __del__ is
trying to return, which calls __del__ again, etc etc etc.
So it's roughly the same as
class C:
def __str__(self):
return str(self)
print C()
You get unbounded recursion and eventually the stack blows
up. "Don't do that" is the best advice <wink>. Reduced
priority accordingly; *maybe* Python can be changed to
detect the stack overflow and give a "maximum recursion
depth" exception instead.
----------------------------------------------------------------------
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=483469&group_id=5470