blob: 11711464214777cdb8a260d2fff835b2b0733128 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#! /usr/bin/env python3
Benjamin Peterson5478b472008-09-17 22:25:09 +00002"""Find the maximum recursion limit that prevents interpreter termination.
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +00003
4This script finds the maximum safe recursion limit on a particular
5platform. If you need to change the recursion limit on your system,
6this script will tell you a safe upper bound. To use the new limit,
Benjamin Peterson5478b472008-09-17 22:25:09 +00007call sys.setrecursionlimit().
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +00008
9This module implements several ways to create infinite recursion in
10Python. Different implementations end up pushing different numbers of
11C stack frames, depending on how many calls through Python's abstract
12C API occur.
13
Benjamin Peterson5478b472008-09-17 22:25:09 +000014After each round of tests, it prints a message:
15"Limit of NNNN is fine".
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +000016
Benjamin Peterson5478b472008-09-17 22:25:09 +000017The highest printed value of "NNNN" is therefore the highest potentially
18safe limit for your system (which depends on the OS, architecture, but also
19the compilation flags). Please note that it is practically impossible to
20test all possible recursion paths in the interpreter, so the results of
21this test should not be trusted blindly -- although they give a good hint
22of which values are reasonable.
23
24NOTE: When the C stack space allocated by your system is exceeded due
25to excessive recursion, exact behaviour depends on the platform, although
26the interpreter will always fail in a likely brutal way: either a
27segmentation fault, a MemoryError, or just a silent abort.
28
29NB: A program that does not use __methods__ can set a higher limit.
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +000030"""
31
32import sys
Amaury Forgeot d'Arcfb1a5eb2008-09-11 21:03:37 +000033import itertools
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +000034
35class RecursiveBlowup1:
36 def __init__(self):
37 self.__init__()
38
39def test_init():
40 return RecursiveBlowup1()
41
42class RecursiveBlowup2:
43 def __repr__(self):
44 return repr(self)
45
46def test_repr():
47 return repr(RecursiveBlowup2())
48
49class RecursiveBlowup4:
50 def __add__(self, x):
51 return x + self
52
53def test_add():
54 return RecursiveBlowup4() + RecursiveBlowup4()
55
56class RecursiveBlowup5:
57 def __getattr__(self, attr):
58 return getattr(self, attr)
59
60def test_getattr():
61 return RecursiveBlowup5().attr
62
63class RecursiveBlowup6:
64 def __getitem__(self, item):
65 return self[item - 2] + self[item - 1]
66
67def test_getitem():
68 return RecursiveBlowup6()[5]
Tim Peters182b5ac2004-07-18 06:16:08 +000069
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +000070def test_recurse():
71 return test_recurse()
72
Amaury Forgeot d'Arcfb1a5eb2008-09-11 21:03:37 +000073def test_cpickle(_cache={}):
74 import io
75 try:
76 import _pickle
77 except ImportError:
78 print("cannot import _pickle, skipped!")
79 return
Antoine Pitroue6d4c5b2011-01-23 17:12:25 +000080 k, l = None, None
Amaury Forgeot d'Arcfb1a5eb2008-09-11 21:03:37 +000081 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):
Antoine Pitroue6d4c5b2011-01-23 17:12:25 +000087 l = [k, l]
88 k = {i: l}
Amaury Forgeot d'Arcfb1a5eb2008-09-11 21:03:37 +000089 _pickle.Pickler(io.BytesIO(), protocol=-1).dump(l)
90 _cache[n] = l
91
Nick Coghlan10d6dde2012-11-05 00:19:18 +100092def test_compiler_recursion():
93 # The compiler uses a scaling factor to support additional levels
94 # of recursion. This is a sanity check of that scaling to ensure
Andrew Svetlov5b898402012-12-18 21:26:36 +020095 # it still raises RuntimeError even at higher recursion limits
Nick Coghlan10d6dde2012-11-05 00:19:18 +100096 compile("()" * (10 * sys.getrecursionlimit()), "<single>", "single")
97
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +000098def check_limit(n, test_func_name):
99 sys.setrecursionlimit(n)
100 if test_func_name.startswith("test_"):
Collin Wintere7bf59f2007-08-30 18:39:28 +0000101 print(test_func_name[5:])
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +0000102 else:
Collin Wintere7bf59f2007-08-30 18:39:28 +0000103 print(test_func_name)
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +0000104 test_func = globals()[test_func_name]
105 try:
106 test_func()
Benjamin Peterson5478b472008-09-17 22:25:09 +0000107 # AttributeError can be raised because of the way e.g. PyDict_GetItem()
108 # silences all exceptions and returns NULL, which is usually interpreted
109 # as "missing attribute".
110 except (RuntimeError, AttributeError):
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +0000111 pass
112 else:
Collin Wintere7bf59f2007-08-30 18:39:28 +0000113 print("Yikes!")
Jeremy Hyltonc18b7d92000-08-31 19:24:17 +0000114
R David Murray54ac8322012-04-04 21:28:14 -0400115if __name__ == '__main__':
116
117 limit = 1000
118 while 1:
119 check_limit(limit, "test_recurse")
120 check_limit(limit, "test_add")
121 check_limit(limit, "test_repr")
122 check_limit(limit, "test_init")
123 check_limit(limit, "test_getattr")
124 check_limit(limit, "test_getitem")
125 check_limit(limit, "test_cpickle")
Nick Coghlan10d6dde2012-11-05 00:19:18 +1000126 check_limit(limit, "test_compiler_recursion")
R David Murray54ac8322012-04-04 21:28:14 -0400127 print("Limit of %d is fine" % limit)
128 limit = limit + 100