forked from nodemcu/nodemcu-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstackbreak.lua
279 lines (236 loc) · 7.62 KB
/
stackbreak.lua
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
-- $Id: api.lua,v 1.147 2016/11/07 13:06:25 roberto Exp $
-- See Copyright Notice in file all.lua
if T==nil then
(Message or print)('\n >>> testC not active: skipping API tests <<<\n')
return
end
local debug = require "debug"
local pack = table.pack
function tcheck (t1, t2)
assert(t1.n == (t2.n or #t2) + 1)
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
end
local function checkerr (msg, f, ...)
local stat, err = pcall(f, ...)
assert(not stat and string.find(err, msg))
end
print('testing C API')
--[=[
do
local f = T.makeCfunc[[
getglobal error
pushstring bola
pcall 1 1 1 # call 'error' with given handler
pushstatus
return 2 # return error message and status
]]
local msg, st = f({}) -- invalid handler
assert(st == "ERRERR" and string.find(msg, "error handling"))
local msg, st = f(nil) -- invalid handler
assert(st == "ERRERR" and string.find(msg, "error handling"))
local a = setmetatable({}, {__call = function (_, x) return x:upper() end})
local msg, st = f(a) -- callable handler
assert(st == "ERRRUN" and msg == "BOLA")
end
do -- test returning more results than fit in the caller stack
local a = {}
for i=1,1000 do a[i] = true end; a[999] = 10
local b = T.testC([[pcall 1 -1 0; pop 1; tostring -1; return 1]],
table.unpack, a)
assert(b == "10")
end
-- testing globals
_G.a = 14; _G.b = "a31"
local a = {T.testC[[
getglobal a;
getglobal b;
getglobal b;
setglobal a;
return *
]]}
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31")
-- colect in cl the `val' of all collected userdata
tt = {}
cl = {n=0}
A = nil; B = nil
local F
F = function (x)
local udval = T.udataval(x)
table.insert(cl, udval)
local d = T.newuserdata(100) -- cria lixo
d = nil
assert(debug.getmetatable(x).__gc == F)
assert(load("table.insert({}, {})"))() -- cria mais lixo
collectgarbage() -- forca coleta de lixo durante coleta!
assert(debug.getmetatable(x).__gc == F) -- coleta anterior nao melou isso?
local dummy = {} -- cria lixo durante coleta
if A ~= nil then
assert(type(A) == "userdata")
assert(T.udataval(A) == B)
debug.getmetatable(A) -- just acess it
end
A = x -- ressucita userdata
B = udval
return 1,2,3
end
tt.__gc = F
-- test whether udate collection frees memory in the right time
do
collectgarbage();
collectgarbage();
local x = collectgarbage("count");
local a = T.newuserdata(5001)
assert(T.testC("objsize 2; return 1", a) == 5001)
assert(collectgarbage("count") >= x+4)
a = nil
collectgarbage();
assert(collectgarbage("count") <= x+1)
-- udata without finalizer
x = collectgarbage("count")
collectgarbage("stop")
for i=1,1000 do T.newuserdata(0) end
assert(collectgarbage("count") > x+10)
collectgarbage()
assert(collectgarbage("count") <= x+1)
-- udata with finalizer
collectgarbage()
x = collectgarbage("count")
collectgarbage("stop")
a = {__gc = function () end}
for i=1,1000 do debug.setmetatable(T.newuserdata(0), a) end
assert(collectgarbage("count") >= x+10)
collectgarbage() -- this collection only calls TM, without freeing memory
assert(collectgarbage("count") >= x+10)
collectgarbage() -- now frees memory
assert(collectgarbage("count") <= x+1)
collectgarbage("restart")
end
collectgarbage("stop")
-- create 3 userdatas with tag `tt'
a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a)
b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b)
c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c)
-- create userdata without meta table
x = T.newuserdata(4)
y = T.newuserdata(0)
-- checkerr("FILE%* expected, got userdata", io.input, a)
-- checkerr("FILE%* expected, got userdata", io.input, x)
assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
d=T.ref(a);
e=T.ref(b);
f=T.ref(c);
t = {T.getref(d), T.getref(e), T.getref(f)}
assert(t[1] == a and t[2] == b and t[3] == c)
t=nil; a=nil; c=nil;
T.unref(e); T.unref(f)
collectgarbage()
]=]
-------------------------------------------------------------------------
-- testing memory limits
-------------------------------------------------------------------------
T.totalmem(T.totalmem()+45*2048) -- set low memory limit
local function fillstack(x,a,b,c,d,e,f,g,h,i)
local j,k,l,m,n,o,p,q,r = a,b,c,d,e,f,g,h,i
if x > 0 then fillstack(x-1,j,k,l,m,n,o,p,q,r) end
end
local calls = 1
local function gcfunc(ud) -- upval: calls
local j,k,l,m,n,o,p,q,r = 0,0,0,0,0,0,0,0,0
print (('GC for %s called with %u fillstacks'):format(tostring(ud),calls))
calls = calls + 10
fillstack(calls,j,k,l,m,n,o,p,q,r)
end
local a ={}
collectgarbage("restart")
collectgarbage("setpause",120)
collectgarbage("setstepmul",1000)
for i = 1, 20 do
local UD = T.newuserdata(2048); debug.setmetatable(UD, {__gc = gcfunc})
a[i] = UD
print (('a[%u] = %s'):format(i, tostring(UD)))
end
for i = 1, 20 do
j = (513 * i % 20) + 1
k = (13 + 257 * i % 20) + 1
calls = calls + 1
local UD = T.newuserdata(2048); debug.setmetatable(UD, {__gc = gcfunc})
print (('setting a[%u] = nil, a[%u] = %s'):format(j, k, tostring(UD)))
a[j]=nil; a[k] = UD
end
print ("Done")
--[=[
checkerr("block too big", T.newuserdata, math.maxinteger)
collectgarbage()
T.totalmem(T.totalmem()+5000) -- set low memory limit (+5k)
checkerr("not enough memory", load"local a={}; for i=1,100000 do a[i]=i end")
T.totalmem(0) -- restore high limit
-- test memory errors; increase memory limit in small steps, so that
-- we get memory errors in different parts of a given task, up to there
-- is enough memory to complete the task without errors
function testamem (s, f)
collectgarbage(); collectgarbage()
local M = T.totalmem()
local oldM = M
local a,b = nil
while 1 do
M = M+7 -- increase memory limit in small steps
T.totalmem(M)
a, b = pcall(f)
T.totalmem(0) -- restore high limit
if a and b then break end -- stop when no more errors
collectgarbage()
if not a and not -- `real' error?
(string.find(b, "memory") or string.find(b, "overflow")) then
error(b, 0) -- propagate it
end
end
print("\nlimit for " .. s .. ": " .. M-oldM)
return b
end
-- testing memory errors when creating a new state
b = testamem("state creation", T.newstate)
T.closestate(b); -- close new state
-- testing luaL_newmetatable
local mt_xuxu, res, top = T.testC("newmetatable xuxu; gettop; return 3")
assert(type(mt_xuxu) == "table" and res and top == 3)
local d, res, top = T.testC("newmetatable xuxu; gettop; return 3")
assert(mt_xuxu == d and not res and top == 3)
d, res, top = T.testC("newmetatable xuxu1; gettop; return 3")
assert(mt_xuxu ~= d and res and top == 3)
x = T.newuserdata(0);
y = T.newuserdata(0);
T.testC("pushstring xuxu; gettable R; setmetatable 2", x)
assert(getmetatable(x) == mt_xuxu)
-- testing luaL_testudata
-- correct metatable
local res1, res2, top = T.testC([[testudata -1 xuxu
testudata 2 xuxu
gettop
return 3]], x)
assert(res1 and res2 and top == 4)
-- wrong metatable
res1, res2, top = T.testC([[testudata -1 xuxu1
testudata 2 xuxu1
gettop
return 3]], x)
assert(not res1 and not res2 and top == 4)
-- non-existent type
res1, res2, top = T.testC([[testudata -1 xuxu2
testudata 2 xuxu2
gettop
return 3]], x)
assert(not res1 and not res2 and top == 4)
-- userdata has no metatable
res1, res2, top = T.testC([[testudata -1 xuxu
testudata 2 xuxu
gettop
return 3]], y)
assert(not res1 and not res2 and top == 4)
-- erase metatables
do
local r = debug.getregistry()
assert(r.xuxu == mt_xuxu and r.xuxu1 == d)
r.xuxu = nil; r.xuxu1 = nil
end
]=]
print'OK'