From 2bd92a59610a08f9444d0e4bca6ce6047716df20 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 11 Oct 2009 21:10:07 +0000 Subject: Move find_recursionlimit.py to Tools/scripts; it is out of place in Misc. --- Misc/HISTORY | 2 +- Misc/NEWS | 2 +- Misc/README | 1 - Misc/find_recursionlimit.py | 117 ----------------------------------- Tools/scripts/find_recursionlimit.py | 117 +++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 120 deletions(-) delete mode 100644 Misc/find_recursionlimit.py create mode 100644 Tools/scripts/find_recursionlimit.py diff --git a/Misc/HISTORY b/Misc/HISTORY index 127b782..43ee01f 100644 --- a/Misc/HISTORY +++ b/Misc/HISTORY @@ -9050,7 +9050,7 @@ limit is the maximum number of recursive calls that can be made by Python code. The limit exists to prevent infinite recursion from overflowing the C stack and causing a core dump. The default value is 1000. The maximum safe value for a particular platform can be found -by running Misc/find_recursionlimit.py. +by running Tools/scripts/find_recursionlimit.py. New Modules and Packages ------------------------ diff --git a/Misc/NEWS b/Misc/NEWS index 9fc3edc..bb94244 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1566,7 +1566,7 @@ Extension Modules Tools/Demos ----------- -- Issue #3850: recursion tests in Misc/find_recursion_limit.py can raise +- Issue #3850: recursion tests in Tools/scripts/find_recursion_limit.py can raise AttributeError instead of RuntimeError, depending in which C API call exactly the recursion limit is exceeded. Consequently, both exception types are caught and silenced. diff --git a/Misc/README b/Misc/README index 920299b..1d8c22d 100644 --- a/Misc/README +++ b/Misc/README @@ -12,7 +12,6 @@ AIX-NOTES Notes for building Python on AIX BeOS-NOTES Notes for building on BeOS BeOS-setup.py setup.py replacement for BeOS, see BeOS-NOTES cheatsheet Quick summary of Python by Ken Manheimer -find_recursionlimit.py Script to find a value for sys.maxrecursionlimit gdbinit Handy stuff to put in your .gdbinit file, if you use gdb HISTORY News from previous releases -- oldest last HPUX-NOTES Notes about dynamic loading under HP-UX diff --git a/Misc/find_recursionlimit.py b/Misc/find_recursionlimit.py deleted file mode 100644 index 88e9bb5..0000000 --- a/Misc/find_recursionlimit.py +++ /dev/null @@ -1,117 +0,0 @@ -#! /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={}): - try: - import cPickle - except ImportError: - print "cannot import cPickle, 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] - cPickle.dumps(l, protocol=-1) - _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 diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py new file mode 100644 index 0000000..88e9bb5 --- /dev/null +++ b/Tools/scripts/find_recursionlimit.py @@ -0,0 +1,117 @@ +#! /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={}): + try: + import cPickle + except ImportError: + print "cannot import cPickle, 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] + cPickle.dumps(l, protocol=-1) + _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 -- cgit v0.12