diff options
author | Georg Brandl <georg@python.org> | 2009-10-11 21:24:34 (GMT) |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2009-10-11 21:24:34 (GMT) |
commit | 93d15cd2518921ed01731f90e1ed1ecd3945c8bc (patch) | |
tree | 3abfd823a07fec154f03977a0ea7aaf84c43f345 /Tools/scripts | |
parent | 320b8010e7b6cfabe4bbed41a6a86a2dc1bd8343 (diff) | |
download | cpython-93d15cd2518921ed01731f90e1ed1ecd3945c8bc.zip cpython-93d15cd2518921ed01731f90e1ed1ecd3945c8bc.tar.gz cpython-93d15cd2518921ed01731f90e1ed1ecd3945c8bc.tar.bz2 |
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.
........
Diffstat (limited to 'Tools/scripts')
-rw-r--r-- | Tools/scripts/README | 11 | ||||
-rw-r--r-- | Tools/scripts/find_recursionlimit.py | 118 |
2 files changed, 124 insertions, 5 deletions
diff --git a/Tools/scripts/README b/Tools/scripts/README index 64fc2bd..b1c167e 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -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) diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py new file mode 100644 index 0000000..2e202be --- /dev/null +++ b/Tools/scripts/find_recursionlimit.py @@ -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 |