---
source: src/main.rs
expression: compiled
input_file: test-data/lua5.4-tests/cstack.lua
---
local tracegc = require("tracegc")
print("testing stack overflow detection");
local fn checkerror(msg, f, ...) {
local s, err = pcall(f, ...)
assert(!s && string.find(err, msg));
}
{
print("testing stack overflow in message handling");
local count = 0
local fn loop(x, y, z) {
count = count + 1
return 1 + loop(x, y, z)
}
tracegc.stop();
local res, msg = xpcall(loop, loop)
tracegc.start();
assert(msg == "error in error handling");
print("final count: ", count);
}
{
print("testing recursion inside pattern matching");
local fn f(size) {
local s = string.rep("a", size)
local p = string.rep(".?", size)
return string.match(s, p)
}
local m = f(80)
assert(#m == 80);
checkerror("too complex", f, 2000);
}
{
print("testing stack-overflow in recursive 'gsub'");
local count = 0
local fn foo() {
count = count + 1
string.gsub("a", ".", foo);
}
checkerror("stack overflow", foo);
print("final count: ", count);
print("testing stack-overflow in recursive 'gsub' with metatables");
local count = 0
local t = setmetatable({}, {
__index = foo
})
foo = fn () {
count = count + 1
string.gsub("a", ".", t);
}
checkerror("stack overflow", foo);
print("final count: ", count);
}
{
print("testing limits in coroutines inside deep calls");
local count = 0
local lim = 1000
local fn stack(n) {
if n > 0 {
return stack(n - 1) + 1
} else {
coroutine.wrap(fn () {
count = count + 1
stack(lim);
})();
}
}
local st, msg = xpcall(stack, fn () {
return "ok"
}, lim)
assert(!st && msg == "ok");
print("final count: ", count);
}
{
print("nesting of resuming yielded coroutines");
local count = 0
local fn body() {
coroutine.yield();
local f = coroutine.wrap(body)
f();
count = count + 1
f();
}
local f = coroutine.wrap(body)
f();
assert(!pcall(f));
print("final count: ", count);
}
{
print("nesting coroutines running after recoverable errors");
local count = 0
local fn foo() {
count = count + 1
pcall(1);
coroutine.wrap(foo)();
}
checkerror("C stack overflow", foo);
print("final count: ", count);
}
if T {
print("testing stack recovery");
local N = 0
local LIM = -1
local stack1
local dummy
local fn err(msg) {
assert(string.find(msg, "stack overflow"));
local _, stacknow = T.stacklevel()
assert(stacknow == stack1 + 200);
}
local fn f() {
dummy, stack1 = T.stacklevel()
if N == LIM {
xpcall(f, err);
local _, stacknow = T.stacklevel()
assert(stacknow == stack1);
return
}
N = N + 1
f();
}
local topB, sizeB
local topA, sizeA
topB, sizeB = T.stacklevel()
tracegc.stop();
xpcall(f, err);
tracegc.start();
topA, sizeA = T.stacklevel()
assert(topA == topB && sizeA < sizeB * 2);
print(string.format("maximum stack size: %d", stack1));
LIM = N
N = 0
tracegc.stop();
f();
tracegc.start();
print("+");
}
print('OK');