~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Misc/find_recursionlimit.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
"""Find the maximum recursion limit that prevents interpreter termination.
 
3
 
 
4
This script finds the maximum safe recursion limit on a particular
 
5
platform.  If you need to change the recursion limit on your system,
 
6
this script will tell you a safe upper bound.  To use the new limit,
 
7
call sys.setrecursionlimit().
 
8
 
 
9
This module implements several ways to create infinite recursion in
 
10
Python.  Different implementations end up pushing different numbers of
 
11
C stack frames, depending on how many calls through Python's abstract
 
12
C API occur.
 
13
 
 
14
After each round of tests, it prints a message:
 
15
"Limit of NNNN is fine".
 
16
 
 
17
The highest printed value of "NNNN" is therefore the highest potentially
 
18
safe limit for your system (which depends on the OS, architecture, but also
 
19
the compilation flags). Please note that it is practically impossible to
 
20
test all possible recursion paths in the interpreter, so the results of
 
21
this test should not be trusted blindly -- although they give a good hint
 
22
of which values are reasonable.
 
23
 
 
24
NOTE: When the C stack space allocated by your system is exceeded due
 
25
to excessive recursion, exact behaviour depends on the platform, although
 
26
the interpreter will always fail in a likely brutal way: either a
 
27
segmentation fault, a MemoryError, or just a silent abort.
 
28
 
 
29
NB: A program that does not use __methods__ can set a higher limit.
 
30
"""
 
31
 
 
32
import sys
 
33
import itertools
 
34
 
 
35
class RecursiveBlowup1:
 
36
    def __init__(self):
 
37
        self.__init__()
 
38
 
 
39
def test_init():
 
40
    return RecursiveBlowup1()
 
41
 
 
42
class RecursiveBlowup2:
 
43
    def __repr__(self):
 
44
        return repr(self)
 
45
 
 
46
def test_repr():
 
47
    return repr(RecursiveBlowup2())
 
48
 
 
49
class RecursiveBlowup4:
 
50
    def __add__(self, x):
 
51
        return x + self
 
52
 
 
53
def test_add():
 
54
    return RecursiveBlowup4() + RecursiveBlowup4()
 
55
 
 
56
class RecursiveBlowup5:
 
57
    def __getattr__(self, attr):
 
58
        return getattr(self, attr)
 
59
 
 
60
def test_getattr():
 
61
    return RecursiveBlowup5().attr
 
62
 
 
63
class RecursiveBlowup6:
 
64
    def __getitem__(self, item):
 
65
        return self[item - 2] + self[item - 1]
 
66
 
 
67
def test_getitem():
 
68
    return RecursiveBlowup6()[5]
 
69
 
 
70
def test_recurse():
 
71
    return test_recurse()
 
72
 
 
73
def test_cpickle(_cache={}):
 
74
    import io
 
75
    try:
 
76
        import _pickle
 
77
    except ImportError:
 
78
        print("cannot import _pickle, skipped!")
 
79
        return
 
80
    l = None
 
81
    for n in itertools.count():
 
82
        try:
 
83
            l = _cache[n]
 
84
            continue  # Already tried and it works, let's save some time
 
85
        except KeyError:
 
86
            for i in range(100):
 
87
                l = [l]
 
88
        _pickle.Pickler(io.BytesIO(), protocol=-1).dump(l)
 
89
        _cache[n] = l
 
90
 
 
91
def check_limit(n, test_func_name):
 
92
    sys.setrecursionlimit(n)
 
93
    if test_func_name.startswith("test_"):
 
94
        print(test_func_name[5:])
 
95
    else:
 
96
        print(test_func_name)
 
97
    test_func = globals()[test_func_name]
 
98
    try:
 
99
        test_func()
 
100
    # AttributeError can be raised because of the way e.g. PyDict_GetItem()
 
101
    # silences all exceptions and returns NULL, which is usually interpreted
 
102
    # as "missing attribute".
 
103
    except (RuntimeError, AttributeError):
 
104
        pass
 
105
    else:
 
106
        print("Yikes!")
 
107
 
 
108
limit = 1000
 
109
while 1:
 
110
    check_limit(limit, "test_recurse")
 
111
    check_limit(limit, "test_add")
 
112
    check_limit(limit, "test_repr")
 
113
    check_limit(limit, "test_init")
 
114
    check_limit(limit, "test_getattr")
 
115
    check_limit(limit, "test_getitem")
 
116
    check_limit(limit, "test_cpickle")
 
117
    print("Limit of %d is fine" % limit)
 
118
    limit = limit + 100