ยปCore Development>Code coverage>Tools/scripts/find_recursionlimit.py

Python code coverage for Tools/scripts/find_recursionlimit.py

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