From 287b302acb8d925178e9edb800f0a8d18c7d35f6 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 23 Sep 2020 10:18:01 -0300 Subject: Revision of stackless implementation - more organized handling of 'nCcalls' - comments - deprecation of 'setcstacklimit' --- testes/cstack.lua | 137 ++++++++++++------------------------------------------ testes/errors.lua | 3 +- 2 files changed, 32 insertions(+), 108 deletions(-) (limited to 'testes') 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 @@ -- $Id: testes/cstack.lua $ -- See Copyright Notice in file all.lua -do return end - -local debug = require "debug" print"testing C-stack overflow detection" -print"If this test crashes, see its file ('cstack.lua')" -- Segmentation faults in these tests probably result from a C-stack --- overflow. To avoid these errors, you can use the function --- 'debug.setcstacklimit' to set a smaller limit for the use of --- C stack by Lua. After finding a reliable limit, you might want --- to recompile Lua with this limit as the value for --- the constant 'LUAI_MAXCCALLS', which defines the default limit. --- (The default limit is printed by this test.) +-- overflow. To avoid these errors, you should set a smaller limit for +-- the use of C stack by Lua, by changing the constant 'LUAI_MAXCCALLS'. -- Alternatively, you can ensure a larger stack for the program. --- For Linux, a limit up to 30_000 seems Ok. Windows cannot go much --- higher than 2_000. - - --- get and print original limit -local origlimit = debug.setcstacklimit(400) -print("default stack limit: " .. origlimit) - - --- Do the tests using the original limit. Or else you may want to change --- 'currentlimit' to lower values to avoid a seg. fault or to higher --- values to check whether they are reliable. -local currentlimit = origlimit -debug.setcstacklimit(currentlimit) -print("current stack limit: " .. currentlimit) - local function checkerror (msg, f, ...) local s, err = pcall(f, ...) assert(not s and string.find(err, msg)) end --- auxiliary function to keep 'count' on the screen even if the program --- crashes. -local count -local back = string.rep("\b", 8) -local function progress () - count = count + 1 - local n = string.format("%-8d", count) - io.stderr:write(back, n) -- erase previous value and write new one -end - - -do print("testing simple recursion:") - count = 0 - local function foo () - progress() - foo() -- do recursive calls until a stack error (or crash) - end - checkerror("stack overflow", foo) - print("\tfinal count: ", count) -end - - do print("testing stack overflow in message handling") - count = 0 + local count = 0 local function loop (x, y, z) - progress() + count = count + 1 return 1 + loop(x, y, z) end local res, msg = xpcall(loop, loop) assert(msg == "error in error handling") - print("\tfinal count: ", count) + print("final count: ", count) end @@ -82,97 +36,66 @@ do print("testing recursion inside pattern matching") end local m = f(80) assert(#m == 80) - checkerror("too complex", f, 200000) + checkerror("too complex", f, 2000) end do print("testing stack-overflow in recursive 'gsub'") - count = 0 + local count = 0 local function foo () - progress() + count = count + 1 string.gsub("a", ".", foo) end checkerror("stack overflow", foo) - print("\tfinal count: ", count) + print("final count: ", count) print("testing stack-overflow in recursive 'gsub' with metatables") - count = 0 + local count = 0 local t = setmetatable({}, {__index = foo}) foo = function () count = count + 1 - progress(count) string.gsub("a", ".", t) end checkerror("stack overflow", foo) - print("\tfinal count: ", count) + print("final count: ", count) end + do -- bug in 5.4.0 print("testing limits in coroutines inside deep calls") - count = 0 + local count = 0 local lim = 1000 local function stack (n) - progress() if n > 0 then return stack(n - 1) + 1 else coroutine.wrap(function () + count = count + 1 stack(lim) end)() end end - print(xpcall(stack, function () return "ok" end, lim)) + local st, msg = xpcall(stack, function () return "ok" end, lim) + assert(not st and msg == "ok") + print("final count: ", count) end -do print("testing changes in C-stack limit") +do + print("nesting of resuming yielded coroutines") + local count = 0 - -- Just an alternative limit, different from the current one - -- (smaller to avoid stack overflows) - local alterlimit = currentlimit * 8 // 10 - - assert(not debug.setcstacklimit(0)) -- limit too small - assert(not debug.setcstacklimit(50000)) -- limit too large - local co = coroutine.wrap (function () - return debug.setcstacklimit(alterlimit) - end) - assert(not co()) -- cannot change C stack inside coroutine - - local n - local function foo () n = n + 1; foo () end - - local function check () - n = 0 - pcall(foo) - return n + local function body () + coroutine.yield() + local f = coroutine.wrap(body) + f(); -- start new coroutine (will stop in previous yield) + count = count + 1 + f() -- call it recursively end - -- set limit to 'alterlimit' - assert(debug.setcstacklimit(alterlimit) == currentlimit) - local limalter = check() - -- set a very low limit (given that there are already several active - -- calls to arrive here) - local lowlimit = 38 - assert(debug.setcstacklimit(lowlimit) == alterlimit) - -- usable limit is much lower, due to active calls - local actuallow = check() - assert(actuallow < lowlimit - 30) - -- now, add 'lowlimit' extra slots, which should all be available - assert(debug.setcstacklimit(lowlimit + lowlimit) == lowlimit) - local lim2 = check() - assert(lim2 == actuallow + lowlimit) - - - -- 'setcstacklimit' works inside protected calls. (The new stack - -- limit is kept when 'pcall' returns.) - assert(pcall(function () - assert(debug.setcstacklimit(alterlimit) == lowlimit * 2) - assert(check() <= limalter) - end)) - - assert(check() == limalter) - -- restore original limit - assert(debug.setcstacklimit(origlimit) == alterlimit) + local f = coroutine.wrap(body) + f() + assert(not pcall(f)) + print("final count: ", count) end - 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) end s = init .. string.rep(rep, 500) local res, msg = load(s) -- 500 levels not ok - assert(not res and string.find(msg, "too many")) + assert(not res and (string.find(msg, "too many") or + string.find(msg, "overflow"))) end testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment -- cgit v1.2.3-55-g6feb