This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: recursion core dumps
Type: Stage:
Components: Interpreter Core Versions:
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: jengeldk, josiahcarlson, logistix, tim.peters
Priority: normal Keywords:

Created on 2005-01-26 17:18 by jengeldk, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (4)
msg24058 - (view) Author: Jacob Engelbrecht (jengeldk) Date: 2005-01-26 17:18
when running recursive function you get a coredump with
deep recursion. 
eg

from sys import *
n = 30000
setrecursionlimit(n+1)

def fact(n):
   if n==1:
      return 1
   return fact(n-1)*n

fact(n)

This is seen on linux i686 with both python2.3 and
python2.4, the recursion depth which triggers the core
dump is 26211 with python2.4 and 29123 with python2.3
with a machine having 2076860 kB of memory, on machines
with less memory smaller numbers are seen.

this is what gdb tells me:
jacob@pauling:/scratch/jacob$ gdb /usr/bin/python2.4 core
GNU gdb 6.3-debian
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public
License, and you are
welcome to change it and/or distribute copies of it
under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show
warranty" for details.
This GDB was configured as "i386-linux"...(no debugging
symbols found)
Using host libthread_db library
"/lib/tls/libthread_db.so.1".

(no debugging symbols found)
Core was generated by `python2.4 /home/user_4/jacob/rr
30000'.
Program terminated with signal 11, Segmentation fault.

warning: current_sos: Can't read pathname for load map:
Input/output error

Reading symbols from /lib/tls/libpthread.so.0...(no
debugging symbols found)...done.
Loaded symbols for /lib/tls/libpthread.so.0
Reading symbols from /lib/tls/libdl.so.2...(no
debugging symbols found)...done.
Loaded symbols for /lib/tls/libdl.so.2
Reading symbols from /lib/tls/libutil.so.1...(no
debugging symbols found)...done.
Loaded symbols for /lib/tls/libutil.so.1
Reading symbols from /lib/tls/libm.so.6...
(no debugging symbols found)...done.
Loaded symbols for /lib/tls/libm.so.6
Reading symbols from /lib/tls/libc.so.6...(no debugging
symbols found)...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging
symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2

#0  0x400c94bf in mallopt () from /lib/tls/libc.so.6
msg24059 - (view) Author: Grant Olson (logistix) Date: 2005-01-29 20:12
Logged In: YES 
user_id=699438

This looks like a stack overflow.  There's not much python 
can do when the stack runs out of memory, which is why the 
default recursion limit is set to 1000.

Also, at least in the reproducable, the number you are building 
is going to consume excessive amounts of memory.

I ran this test (to avoid creating a giant long number) and still 
got the segfault.

from sys import *
n = 30000
setrecursionlimit(n+1)

def nofact(n):
    if n==1: 
        return 1
    return nofact(n-1)

nofact(n)
msg24060 - (view) Author: Josiah Carlson (josiahcarlson) * (Python triager) Date: 2005-01-29 20:16
Logged In: YES 
user_id=341410

The fact that an error occurs is not surprising.  Python is
limited by the C stack size, which from what I understand is
well below 2GB.

The fact that it gets to nearly 30k levels of recursion for
you is amazing to me, the most used platform (Windows) can
only ever get to around 5500 levels before they get
"MemoryError: stack overflow" exceptions.

I believe that the reason you are getting a segfault on
linux is the way the linux malloc() and free() work. 
Specifically, malloc() on linux will give you a pointer to
memory, regardless of whether it is available.  If your
program has used up all of its stack space, and you need
more, the pointer will be invalid.  If Python happens to
call a free() before you actually access the invalid
pointer, everything will work.  If Python doesn't call
free() before you access the invalid pointer, you get a
segfault.

Unfortunately, there is no way that Python (or any other
program on linux) can know that the pointer it has gotten
from malloc() is invalid.

Furthermore, as per the docs here:
http://docs.python.org/lib/module-sys.html

"
setrecursionlimit(limit)
Set the maximum depth of the Python interpreter stack to
limit. This limit prevents infinite recursion from causing
an overflow of the C stack and crashing Python.

The highest possible limit is platform-dependent. A user may
need to set the limit higher when she has a program that
requires deep recursion and a platform that supports a
higher limit. This should be done with care, because a
too-high limit can lead to a crash."

I would suggest that this bug be closed as "3rd party, will
not fix", and suggest the OP read the documentation.
msg24061 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2005-01-29 20:20
Logged In: YES 
user_id=31435

The docs for setrecursionlimit() are indeed already quite clear 
that you boost its default value at your own risk.  So this 
isn't a bug, it's a documented limitation.
History
Date User Action Args
2022-04-11 14:56:09adminsetgithub: 41493
2005-01-26 17:18:09jengeldkcreate