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 | try:
|
---|
75 | import cPickle
|
---|
76 | except ImportError:
|
---|
77 | print "cannot import cPickle, skipped!"
|
---|
78 | return
|
---|
79 | l = None
|
---|
80 | for n in itertools.count():
|
---|
81 | try:
|
---|
82 | l = _cache[n]
|
---|
83 | continue # Already tried and it works, let's save some time
|
---|
84 | except KeyError:
|
---|
85 | for i in range(100):
|
---|
86 | l = [l]
|
---|
87 | cPickle.dumps(l, protocol=-1)
|
---|
88 | _cache[n] = l
|
---|
89 |
|
---|
90 | def check_limit(n, test_func_name):
|
---|
91 | sys.setrecursionlimit(n)
|
---|
92 | if test_func_name.startswith("test_"):
|
---|
93 | print test_func_name[5:]
|
---|
94 | else:
|
---|
95 | print test_func_name
|
---|
96 | test_func = globals()[test_func_name]
|
---|
97 | try:
|
---|
98 | test_func()
|
---|
99 | # AttributeError can be raised because of the way e.g. PyDict_GetItem()
|
---|
100 | # silences all exceptions and returns NULL, which is usually interpreted
|
---|
101 | # as "missing attribute".
|
---|
102 | except (RuntimeError, AttributeError):
|
---|
103 | pass
|
---|
104 | else:
|
---|
105 | print "Yikes!"
|
---|
106 |
|
---|
107 | limit = 1000
|
---|
108 | while 1:
|
---|
109 | check_limit(limit, "test_recurse")
|
---|
110 | check_limit(limit, "test_add")
|
---|
111 | check_limit(limit, "test_repr")
|
---|
112 | check_limit(limit, "test_init")
|
---|
113 | check_limit(limit, "test_getattr")
|
---|
114 | check_limit(limit, "test_getitem")
|
---|
115 | check_limit(limit, "test_cpickle")
|
---|
116 | print "Limit of %d is fine" % limit
|
---|
117 | limit = limit + 100
|
---|