Merged revisions 75370-75372 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r75370 | georg.brandl | 2009-10-11 23:10:07 +0200 (So, 11 Okt 2009) | 1 line

  Move find_recursionlimit.py to Tools/scripts; it is out of place in Misc.
........
  r75371 | georg.brandl | 2009-10-11 23:14:37 +0200 (So, 11 Okt 2009) | 1 line

  Add find_recursionlimit.py to README.
........
  r75372 | georg.brandl | 2009-10-11 23:17:14 +0200 (So, 11 Okt 2009) | 1 line

  Update Misc/README.
........
This commit is contained in:
Georg Brandl 2009-10-11 21:24:34 +00:00
parent 320b8010e7
commit 93d15cd251
4 changed files with 19 additions and 10 deletions

View file

@ -19,7 +19,8 @@ db2pickle.py Dump a database file to a pickle
diff.py Print file diffs in context, unified, or ndiff formats
dutree.py Format du(1) output as a tree sorted by size
eptags.py Create Emacs TAGS file for Python modules
finddiv.py A grep-like tool that looks for division operators.
find_recursionlimit.py Find the maximum recursion limit on this machine
finddiv.py A grep-like tool that looks for division operators
findlinksto.py Recursively find symbolic links to a given path prefix
findnocoding.py Find source files which need an encoding declaration
fixcid.py Massive identifier substitution on C source files
@ -28,8 +29,8 @@ fixheader.py Add some cpp magic to a C include file
fixnotice.py Fix the copyright notice in source files
fixps.py Fix Python scripts' first line (if #!)
ftpmirror.py FTP mirror script
google.py Open a webbrowser with Google.
gprof2html.py Transform gprof(1) output into useful HTML.
google.py Open a webbrowser with Google
gprof2html.py Transform gprof(1) output into useful HTML
h2py.py Translate #define's into Python assignments
idle Main program to start IDLE
ifdef.py Remove #if(n)def groups from C sources
@ -55,9 +56,9 @@ pysource.py Find Python source files
redemo.py Basic regular expression demonstration facility
reindent.py Change .py files to use 4-space indents.
rgrep.py Reverse grep through a file (useful for big logfiles)
setup.py Install all scripts listed here.
setup.py Install all scripts listed here
suff.py Sort a list of files by suffix
svneol.py Sets svn:eol-style on all files in directory.
svneol.py Sets svn:eol-style on all files in directory
texcheck.py Validate Python LaTeX formatting (Raymond Hettinger)
texi2html.py Convert GNU texinfo files into HTML
treesync.py Synchronize source trees (very ideosyncratic)

View file

@ -0,0 +1,118 @@
#! /usr/bin/env python
"""Find the maximum recursion limit that prevents interpreter termination.
This script finds the maximum safe recursion limit on a particular
platform. If you need to change the recursion limit on your system,
this script will tell you a safe upper bound. To use the new limit,
call sys.setrecursionlimit().
This module implements several ways to create infinite recursion in
Python. Different implementations end up pushing different numbers of
C stack frames, depending on how many calls through Python's abstract
C API occur.
After each round of tests, it prints a message:
"Limit of NNNN is fine".
The highest printed value of "NNNN" is therefore the highest potentially
safe limit for your system (which depends on the OS, architecture, but also
the compilation flags). Please note that it is practically impossible to
test all possible recursion paths in the interpreter, so the results of
this test should not be trusted blindly -- although they give a good hint
of which values are reasonable.
NOTE: When the C stack space allocated by your system is exceeded due
to excessive recursion, exact behaviour depends on the platform, although
the interpreter will always fail in a likely brutal way: either a
segmentation fault, a MemoryError, or just a silent abort.
NB: A program that does not use __methods__ can set a higher limit.
"""
import sys
import itertools
class RecursiveBlowup1:
def __init__(self):
self.__init__()
def test_init():
return RecursiveBlowup1()
class RecursiveBlowup2:
def __repr__(self):
return repr(self)
def test_repr():
return repr(RecursiveBlowup2())
class RecursiveBlowup4:
def __add__(self, x):
return x + self
def test_add():
return RecursiveBlowup4() + RecursiveBlowup4()
class RecursiveBlowup5:
def __getattr__(self, attr):
return getattr(self, attr)
def test_getattr():
return RecursiveBlowup5().attr
class RecursiveBlowup6:
def __getitem__(self, item):
return self[item - 2] + self[item - 1]
def test_getitem():
return RecursiveBlowup6()[5]
def test_recurse():
return test_recurse()
def test_cpickle(_cache={}):
import io
try:
import _pickle
except ImportError:
print("cannot import _pickle, skipped!")
return
l = None
for n in itertools.count():
try:
l = _cache[n]
continue # Already tried and it works, let's save some time
except KeyError:
for i in range(100):
l = [l]
_pickle.Pickler(io.BytesIO(), protocol=-1).dump(l)
_cache[n] = l
def check_limit(n, test_func_name):
sys.setrecursionlimit(n)
if test_func_name.startswith("test_"):
print(test_func_name[5:])
else:
print(test_func_name)
test_func = globals()[test_func_name]
try:
test_func()
# AttributeError can be raised because of the way e.g. PyDict_GetItem()
# silences all exceptions and returns NULL, which is usually interpreted
# as "missing attribute".
except (RuntimeError, AttributeError):
pass
else:
print("Yikes!")
limit = 1000
while 1:
check_limit(limit, "test_recurse")
check_limit(limit, "test_add")
check_limit(limit, "test_repr")
check_limit(limit, "test_init")
check_limit(limit, "test_getattr")
check_limit(limit, "test_getitem")
check_limit(limit, "test_cpickle")
print("Limit of %d is fine" % limit)
limit = limit + 100