aboutsummaryrefslogtreecommitdiff
path: root/testes/cstack.lua
blob: c7aa740f014fc483853b6f62aac2e00bfde31ac4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
-- $Id: testes/cstack.lua $
-- See Copyright Notice in file all.lua

local debug = require "debug"

print"testing C-stack overflow detection"

local origlimit = debug.setCstacklimit(400)
print("current stack limit: " .. origlimit)
debug.setCstacklimit(origlimit)

-- Segmentation faults in these tests probably result from a C-stack
-- overflow. To avoid these errors, recompile Lua with a smaller
-- value for the constant 'LUAI_MAXCCALLS' or else ensure a larger
-- stack for the program.

local function checkerror (msg, f, ...)
  local s, err = pcall(f, ...)
  assert(not s and string.find(err, msg))
end

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)
end


do    print("testing simple recursion:")
  count = 0
  local function foo ()
    progress()
    foo()
  end
  checkerror("stack overflow", foo)
  print("\tfinal count: ", count)
end


do  print("testing stack overflow in message handling")
  count = 0
  local function loop (x, y, z)
    progress()
    return 1 + loop(x, y, z)
  end
  local res, msg = xpcall(loop, loop)
  assert(msg == "error in error handling")
  print("\tfinal count: ", count)
end


-- bug since 2.5 (C-stack overflow in recursion inside pattern matching)
do  print("testing recursion inside pattern matching")
  local function f (size)
    local s = string.rep("a", size)
    local p = string.rep(".?", size)
    return string.match(s, p)
  end
  local m = f(80)
  assert(#m == 80)
  checkerror("too complex", f, 200000)
end


do  print("testing stack-overflow in recursive 'gsub'")
  count = 0
  local function foo ()
    progress()
    string.gsub("a", ".", foo)
  end
  checkerror("stack overflow", foo)
  print("\tfinal count: ", count)

  print("testing stack-overflow in recursive 'gsub' with metatables")
  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)
end


do  print("testing changes in C-stack limit")

  assert(not debug.setCstacklimit(0))        -- limit too small
  assert(not debug.setCstacklimit(50000))    -- limit too large
  local co = coroutine.wrap (function ()
               return debug.setCstacklimit(400)
             end)
  assert(co() == false)         -- 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
  end

  assert(debug.setCstacklimit(400) == origlimit)
  local lim400 = check()
  -- a very low limit (given that the several calls to arive here)
  local lowlimit = 38
  assert(debug.setCstacklimit(lowlimit) == 400)
  assert(check() < lowlimit - 30)
  assert(debug.setCstacklimit(600) == lowlimit)
  local lim600 = check()
  assert(lim600 == lim400 + 200)


  -- 'setCstacklimit' works inside protected calls. (The new stack
  -- limit is kept when 'pcall' returns.)
  assert(pcall(function ()
    assert(debug.setCstacklimit(400) == 600)
    assert(check() <= lim400)
  end))

  assert(check() == lim400)
  assert(debug.setCstacklimit(origlimit) == 400)   -- restore original limit
end


print'OK'