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 |
