diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-09-23 10:18:01 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-10-12 12:29:09 -0300 |
commit | 287b302acb8d925178e9edb800f0a8d18c7d35f6 (patch) | |
tree | bd662481ea995dc8c050324d553146e870434d93 /testes | |
parent | 5d8ce05b3f6fad79e37ed21c1076e47a322472c6 (diff) | |
download | lua-287b302acb8d925178e9edb800f0a8d18c7d35f6.tar.gz lua-287b302acb8d925178e9edb800f0a8d18c7d35f6.tar.bz2 lua-287b302acb8d925178e9edb800f0a8d18c7d35f6.zip |
Revision of stackless implementation
- more organized handling of 'nCcalls'
- comments
- deprecation of 'setcstacklimit'
Diffstat (limited to 'testes')
-rw-r--r-- | testes/cstack.lua | 137 | ||||
-rw-r--r-- | testes/errors.lua | 3 |
2 files changed, 32 insertions, 108 deletions
diff --git a/testes/cstack.lua b/testes/cstack.lua index c1177f3b..5767adf6 100644 --- a/testes/cstack.lua +++ b/testes/cstack.lua | |||
@@ -1,75 +1,29 @@ | |||
1 | -- $Id: testes/cstack.lua $ | 1 | -- $Id: testes/cstack.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file all.lua |
3 | 3 | ||
4 | do return end | ||
5 | |||
6 | local debug = require "debug" | ||
7 | 4 | ||
8 | print"testing C-stack overflow detection" | 5 | print"testing C-stack overflow detection" |
9 | print"If this test crashes, see its file ('cstack.lua')" | ||
10 | 6 | ||
11 | -- Segmentation faults in these tests probably result from a C-stack | 7 | -- Segmentation faults in these tests probably result from a C-stack |
12 | -- overflow. To avoid these errors, you can use the function | 8 | -- overflow. To avoid these errors, you should set a smaller limit for |
13 | -- 'debug.setcstacklimit' to set a smaller limit for the use of | 9 | -- the use of C stack by Lua, by changing the constant 'LUAI_MAXCCALLS'. |
14 | -- C stack by Lua. After finding a reliable limit, you might want | ||
15 | -- to recompile Lua with this limit as the value for | ||
16 | -- the constant 'LUAI_MAXCCALLS', which defines the default limit. | ||
17 | -- (The default limit is printed by this test.) | ||
18 | -- Alternatively, you can ensure a larger stack for the program. | 10 | -- Alternatively, you can ensure a larger stack for the program. |
19 | 11 | ||
20 | -- For Linux, a limit up to 30_000 seems Ok. Windows cannot go much | ||
21 | -- higher than 2_000. | ||
22 | |||
23 | |||
24 | -- get and print original limit | ||
25 | local origlimit <const> = debug.setcstacklimit(400) | ||
26 | print("default stack limit: " .. origlimit) | ||
27 | |||
28 | |||
29 | -- Do the tests using the original limit. Or else you may want to change | ||
30 | -- 'currentlimit' to lower values to avoid a seg. fault or to higher | ||
31 | -- values to check whether they are reliable. | ||
32 | local currentlimit <const> = origlimit | ||
33 | debug.setcstacklimit(currentlimit) | ||
34 | print("current stack limit: " .. currentlimit) | ||
35 | |||
36 | 12 | ||
37 | local function checkerror (msg, f, ...) | 13 | local function checkerror (msg, f, ...) |
38 | local s, err = pcall(f, ...) | 14 | local s, err = pcall(f, ...) |
39 | assert(not s and string.find(err, msg)) | 15 | assert(not s and string.find(err, msg)) |
40 | end | 16 | end |
41 | 17 | ||
42 | -- auxiliary function to keep 'count' on the screen even if the program | ||
43 | -- crashes. | ||
44 | local count | ||
45 | local back = string.rep("\b", 8) | ||
46 | local function progress () | ||
47 | count = count + 1 | ||
48 | local n = string.format("%-8d", count) | ||
49 | io.stderr:write(back, n) -- erase previous value and write new one | ||
50 | end | ||
51 | |||
52 | |||
53 | do print("testing simple recursion:") | ||
54 | count = 0 | ||
55 | local function foo () | ||
56 | progress() | ||
57 | foo() -- do recursive calls until a stack error (or crash) | ||
58 | end | ||
59 | checkerror("stack overflow", foo) | ||
60 | print("\tfinal count: ", count) | ||
61 | end | ||
62 | |||
63 | |||
64 | do print("testing stack overflow in message handling") | 18 | do print("testing stack overflow in message handling") |
65 | count = 0 | 19 | local count = 0 |
66 | local function loop (x, y, z) | 20 | local function loop (x, y, z) |
67 | progress() | 21 | count = count + 1 |
68 | return 1 + loop(x, y, z) | 22 | return 1 + loop(x, y, z) |
69 | end | 23 | end |
70 | local res, msg = xpcall(loop, loop) | 24 | local res, msg = xpcall(loop, loop) |
71 | assert(msg == "error in error handling") | 25 | assert(msg == "error in error handling") |
72 | print("\tfinal count: ", count) | 26 | print("final count: ", count) |
73 | end | 27 | end |
74 | 28 | ||
75 | 29 | ||
@@ -82,97 +36,66 @@ do print("testing recursion inside pattern matching") | |||
82 | end | 36 | end |
83 | local m = f(80) | 37 | local m = f(80) |
84 | assert(#m == 80) | 38 | assert(#m == 80) |
85 | checkerror("too complex", f, 200000) | 39 | checkerror("too complex", f, 2000) |
86 | end | 40 | end |
87 | 41 | ||
88 | 42 | ||
89 | do print("testing stack-overflow in recursive 'gsub'") | 43 | do print("testing stack-overflow in recursive 'gsub'") |
90 | count = 0 | 44 | local count = 0 |
91 | local function foo () | 45 | local function foo () |
92 | progress() | 46 | count = count + 1 |
93 | string.gsub("a", ".", foo) | 47 | string.gsub("a", ".", foo) |
94 | end | 48 | end |
95 | checkerror("stack overflow", foo) | 49 | checkerror("stack overflow", foo) |
96 | print("\tfinal count: ", count) | 50 | print("final count: ", count) |
97 | 51 | ||
98 | print("testing stack-overflow in recursive 'gsub' with metatables") | 52 | print("testing stack-overflow in recursive 'gsub' with metatables") |
99 | count = 0 | 53 | local count = 0 |
100 | local t = setmetatable({}, {__index = foo}) | 54 | local t = setmetatable({}, {__index = foo}) |
101 | foo = function () | 55 | foo = function () |
102 | count = count + 1 | 56 | count = count + 1 |
103 | progress(count) | ||
104 | string.gsub("a", ".", t) | 57 | string.gsub("a", ".", t) |
105 | end | 58 | end |
106 | checkerror("stack overflow", foo) | 59 | checkerror("stack overflow", foo) |
107 | print("\tfinal count: ", count) | 60 | print("final count: ", count) |
108 | end | 61 | end |
109 | 62 | ||
63 | |||
110 | do -- bug in 5.4.0 | 64 | do -- bug in 5.4.0 |
111 | print("testing limits in coroutines inside deep calls") | 65 | print("testing limits in coroutines inside deep calls") |
112 | count = 0 | 66 | local count = 0 |
113 | local lim = 1000 | 67 | local lim = 1000 |
114 | local function stack (n) | 68 | local function stack (n) |
115 | progress() | ||
116 | if n > 0 then return stack(n - 1) + 1 | 69 | if n > 0 then return stack(n - 1) + 1 |
117 | else coroutine.wrap(function () | 70 | else coroutine.wrap(function () |
71 | count = count + 1 | ||
118 | stack(lim) | 72 | stack(lim) |
119 | end)() | 73 | end)() |
120 | end | 74 | end |
121 | end | 75 | end |
122 | 76 | ||
123 | print(xpcall(stack, function () return "ok" end, lim)) | 77 | local st, msg = xpcall(stack, function () return "ok" end, lim) |
78 | assert(not st and msg == "ok") | ||
79 | print("final count: ", count) | ||
124 | end | 80 | end |
125 | 81 | ||
126 | 82 | ||
127 | do print("testing changes in C-stack limit") | 83 | do |
84 | print("nesting of resuming yielded coroutines") | ||
85 | local count = 0 | ||
128 | 86 | ||
129 | -- Just an alternative limit, different from the current one | 87 | local function body () |
130 | -- (smaller to avoid stack overflows) | 88 | coroutine.yield() |
131 | local alterlimit <const> = currentlimit * 8 // 10 | 89 | local f = coroutine.wrap(body) |
132 | 90 | f(); -- start new coroutine (will stop in previous yield) | |
133 | assert(not debug.setcstacklimit(0)) -- limit too small | 91 | count = count + 1 |
134 | assert(not debug.setcstacklimit(50000)) -- limit too large | 92 | f() -- call it recursively |
135 | local co = coroutine.wrap (function () | ||
136 | return debug.setcstacklimit(alterlimit) | ||
137 | end) | ||
138 | assert(not co()) -- cannot change C stack inside coroutine | ||
139 | |||
140 | local n | ||
141 | local function foo () n = n + 1; foo () end | ||
142 | |||
143 | local function check () | ||
144 | n = 0 | ||
145 | pcall(foo) | ||
146 | return n | ||
147 | end | 93 | end |
148 | 94 | ||
149 | -- set limit to 'alterlimit' | 95 | local f = coroutine.wrap(body) |
150 | assert(debug.setcstacklimit(alterlimit) == currentlimit) | 96 | f() |
151 | local limalter <const> = check() | 97 | assert(not pcall(f)) |
152 | -- set a very low limit (given that there are already several active | 98 | print("final count: ", count) |
153 | -- calls to arrive here) | ||
154 | local lowlimit <const> = 38 | ||
155 | assert(debug.setcstacklimit(lowlimit) == alterlimit) | ||
156 | -- usable limit is much lower, due to active calls | ||
157 | local actuallow = check() | ||
158 | assert(actuallow < lowlimit - 30) | ||
159 | -- now, add 'lowlimit' extra slots, which should all be available | ||
160 | assert(debug.setcstacklimit(lowlimit + lowlimit) == lowlimit) | ||
161 | local lim2 <const> = check() | ||
162 | assert(lim2 == actuallow + lowlimit) | ||
163 | |||
164 | |||
165 | -- 'setcstacklimit' works inside protected calls. (The new stack | ||
166 | -- limit is kept when 'pcall' returns.) | ||
167 | assert(pcall(function () | ||
168 | assert(debug.setcstacklimit(alterlimit) == lowlimit * 2) | ||
169 | assert(check() <= limalter) | ||
170 | end)) | ||
171 | |||
172 | assert(check() == limalter) | ||
173 | -- restore original limit | ||
174 | assert(debug.setcstacklimit(origlimit) == alterlimit) | ||
175 | end | 99 | end |
176 | 100 | ||
177 | |||
178 | print'OK' | 101 | print'OK' |
diff --git a/testes/errors.lua b/testes/errors.lua index 88918df7..f975b3dd 100644 --- a/testes/errors.lua +++ b/testes/errors.lua | |||
@@ -532,7 +532,8 @@ local function testrep (init, rep, close, repc, finalresult) | |||
532 | end | 532 | end |
533 | s = init .. string.rep(rep, 500) | 533 | s = init .. string.rep(rep, 500) |
534 | local res, msg = load(s) -- 500 levels not ok | 534 | local res, msg = load(s) -- 500 levels not ok |
535 | assert(not res and string.find(msg, "too many")) | 535 | assert(not res and (string.find(msg, "too many") or |
536 | string.find(msg, "overflow"))) | ||
536 | end | 537 | end |
537 | 538 | ||
538 | testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment | 539 | testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment |