aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-03-12 13:52:35 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-03-12 13:52:35 -0300
commit4398e488e678decd06a5ca48a27751d509361405 (patch)
tree8351be35bc54624dbbf2cae5aae312d11845147a
parent808976bb59d91a031d9832b5482a9fb5a41faee3 (diff)
downloadlua-4398e488e678decd06a5ca48a27751d509361405.tar.gz
lua-4398e488e678decd06a5ca48a27751d509361405.tar.bz2
lua-4398e488e678decd06a5ca48a27751d509361405.zip
New test file 'memerr.lua'
Tests for memory-allocation errors moved from 'api.lua' to this new file, as 'api.lua' was already too big. (Besides, these tests have nothing to do with the API.)
-rw-r--r--testes/all.lua1
-rw-r--r--testes/api.lua243
-rw-r--r--testes/memerr.lua266
-rwxr-xr-xtestes/packtests1
4 files changed, 268 insertions, 243 deletions
diff --git a/testes/all.lua b/testes/all.lua
index 4ffa9efe..c3fdac95 100644
--- a/testes/all.lua
+++ b/testes/all.lua
@@ -182,6 +182,7 @@ dofile('nextvar.lua')
182dofile('pm.lua') 182dofile('pm.lua')
183dofile('utf8.lua') 183dofile('utf8.lua')
184dofile('api.lua') 184dofile('api.lua')
185dofile('memerr.lua')
185assert(dofile('events.lua') == 12) 186assert(dofile('events.lua') == 12)
186dofile('vararg.lua') 187dofile('vararg.lua')
187dofile('closure.lua') 188dofile('closure.lua')
diff --git a/testes/api.lua b/testes/api.lua
index 21f703fd..ee2de98b 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -11,9 +11,6 @@ local debug = require "debug"
11local pack = table.pack 11local pack = table.pack
12 12
13 13
14-- standard error message for memory errors
15local MEMERRMSG = "not enough memory"
16
17local function tcheck (t1, t2) 14local function tcheck (t1, t2)
18 assert(t1.n == (t2.n or #t2) + 1) 15 assert(t1.n == (t2.n or #t2) + 1)
19 for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end 16 for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
@@ -432,11 +429,6 @@ do
432 "bad argument #4 (string expected, got no value)") 429 "bad argument #4 (string expected, got no value)")
433 430
434 431
435 -- memory error
436 T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
437 assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
438 T.totalmem(0) -- restore high limit
439
440 -- memory error + thread status 432 -- memory error + thread status
441 local x = T.checkpanic( 433 local x = T.checkpanic(
442 [[ alloccount 0 # force a memory error in next line 434 [[ alloccount 0 # force a memory error in next line
@@ -1306,241 +1298,6 @@ do
1306end 1298end
1307 1299
1308 1300
1309--[[
1310** {==================================================================
1311** Testing memory limits
1312** ===================================================================
1313--]]
1314
1315print("memory-allocation errors")
1316
1317checkerr("block too big", T.newuserdata, math.maxinteger)
1318collectgarbage()
1319local f = load"local a={}; for i=1,100000 do a[i]=i end"
1320T.alloccount(10)
1321checkerr(MEMERRMSG, f)
1322T.alloccount() -- remove limit
1323
1324
1325-- test memory errors; increase limit for maximum memory by steps,
1326-- o that we get memory errors in all allocations of a given
1327-- task, until there is enough memory to complete the task without
1328-- errors.
1329local function testbytes (s, f)
1330 collectgarbage()
1331 local M = T.totalmem()
1332 local oldM = M
1333 local a,b = nil
1334 while true do
1335 collectgarbage(); collectgarbage()
1336 T.totalmem(M)
1337 a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
1338 T.totalmem(0) -- remove limit
1339 if a and b == "OK" then break end -- stop when no more errors
1340 if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
1341 error(a, 0) -- propagate it
1342 end
1343 M = M + 7 -- increase memory limit
1344 end
1345 print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
1346 return a
1347end
1348
1349-- test memory errors; increase limit for number of allocations one
1350-- by one, so that we get memory errors in all allocations of a given
1351-- task, until there is enough allocations to complete the task without
1352-- errors.
1353
1354local function testalloc (s, f)
1355 collectgarbage()
1356 local M = 0
1357 local a,b = nil
1358 while true do
1359 collectgarbage(); collectgarbage()
1360 T.alloccount(M)
1361 a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
1362 T.alloccount() -- remove limit
1363 if a and b == "OK" then break end -- stop when no more errors
1364 if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
1365 error(a, 0) -- propagate it
1366 end
1367 M = M + 1 -- increase allocation limit
1368 end
1369 print(string.format("minimum allocations for %s: %d allocations", s, M))
1370 return a
1371end
1372
1373
1374local function testamem (s, f)
1375 testalloc(s, f)
1376 return testbytes(s, f)
1377end
1378
1379
1380-- doing nothing
1381b = testamem("doing nothing", function () return 10 end)
1382assert(b == 10)
1383
1384-- testing memory errors when creating a new state
1385
1386testamem("state creation", function ()
1387 local st = T.newstate()
1388 if st then T.closestate(st) end -- close new state
1389 return st
1390end)
1391
1392testamem("empty-table creation", function ()
1393 return {}
1394end)
1395
1396testamem("string creation", function ()
1397 return "XXX" .. "YYY"
1398end)
1399
1400testamem("coroutine creation", function()
1401 return coroutine.create(print)
1402end)
1403
1404
1405-- testing to-be-closed variables
1406testamem("to-be-closed variables", function()
1407 local flag
1408 do
1409 local x <close> =
1410 setmetatable({}, {__close = function () flag = true end})
1411 flag = false
1412 local x = {}
1413 end
1414 return flag
1415end)
1416
1417
1418-- testing threads
1419
1420-- get main thread from registry
1421local mt = T.testC("rawgeti R !M; return 1")
1422assert(type(mt) == "thread" and coroutine.running() == mt)
1423
1424
1425
1426local function expand (n,s)
1427 if n==0 then return "" end
1428 local e = string.rep("=", n)
1429 return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
1430 e, s, expand(n-1,s), e)
1431end
1432
1433G=0; collectgarbage(); a =collectgarbage("count")
1434load(expand(20,"G=G+1"))()
1435assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
1436G = nil
1437
1438testamem("running code on new thread", function ()
1439 return T.doonnewstack("local x=1") == 0 -- try to create thread
1440end)
1441
1442
1443-- testing memory x compiler
1444
1445testamem("loadstring", function ()
1446 return load("x=1") -- try to do load a string
1447end)
1448
1449
1450local testprog = [[
1451local function foo () return end
1452local t = {"x"}
1453AA = "aaa"
1454for i = 1, #t do AA = AA .. t[i] end
1455return true
1456]]
1457
1458-- testing memory x dofile
1459_G.AA = nil
1460local t =os.tmpname()
1461local f = assert(io.open(t, "w"))
1462f:write(testprog)
1463f:close()
1464testamem("dofile", function ()
1465 local a = loadfile(t)
1466 return a and a()
1467end)
1468assert(os.remove(t))
1469assert(_G.AA == "aaax")
1470
1471
1472-- other generic tests
1473
1474testamem("gsub", function ()
1475 local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
1476 return (a == 'ablo ablo')
1477end)
1478
1479testamem("dump/undump", function ()
1480 local a = load(testprog)
1481 local b = a and string.dump(a)
1482 a = b and load(b)
1483 return a and a()
1484end)
1485
1486_G.AA = nil
1487
1488local t = os.tmpname()
1489testamem("file creation", function ()
1490 local f = assert(io.open(t, 'w'))
1491 assert (not io.open"nomenaoexistente")
1492 io.close(f);
1493 return not loadfile'nomenaoexistente'
1494end)
1495assert(os.remove(t))
1496
1497testamem("table creation", function ()
1498 local a, lim = {}, 10
1499 for i=1,lim do a[i] = i; a[i..'a'] = {} end
1500 return (type(a[lim..'a']) == 'table' and a[lim] == lim)
1501end)
1502
1503testamem("constructors", function ()
1504 local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
1505 return (type(a) == 'table' and a.e == 5)
1506end)
1507
1508local a = 1
1509local close = nil
1510testamem("closure creation", function ()
1511 function close (b)
1512 return function (x) return b + x end
1513 end
1514 return (close(2)(4) == 6)
1515end)
1516
1517testamem("using coroutines", function ()
1518 local a = coroutine.wrap(function ()
1519 coroutine.yield(string.rep("a", 10))
1520 return {}
1521 end)
1522 assert(string.len(a()) == 10)
1523 return a()
1524end)
1525
1526do -- auxiliary buffer
1527 local lim = 100
1528 local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
1529 testamem("auxiliary buffer", function ()
1530 return (#table.concat(a, ",") == 20*lim + lim - 1)
1531 end)
1532end
1533
1534testamem("growing stack", function ()
1535 local function foo (n)
1536 if n == 0 then return 1 else return 1 + foo(n - 1) end
1537 end
1538 return foo(100)
1539end)
1540
1541-- }==================================================================
1542
1543
1544do -- testing failing in 'lua_checkstack' 1301do -- testing failing in 'lua_checkstack'
1545 local res = T.testC([[rawcheckstack 500000; return 1]]) 1302 local res = T.testC([[rawcheckstack 500000; return 1]])
1546 assert(res == false) 1303 assert(res == false)
diff --git a/testes/memerr.lua b/testes/memerr.lua
new file mode 100644
index 00000000..cb236eb9
--- /dev/null
+++ b/testes/memerr.lua
@@ -0,0 +1,266 @@
1-- $Id: testes/memerr.lua $
2-- See Copyright Notice in file all.lua
3
4
5local function checkerr (msg, f, ...)
6 local stat, err = pcall(f, ...)
7 assert(not stat and string.find(err, msg))
8end
9
10if T==nil then
11 (Message or print)
12 ('\n >>> testC not active: skipping memory error tests <<<\n')
13 return
14end
15
16print("testing memory-allocation errors")
17
18local debug = require "debug"
19
20local pack = table.pack
21
22-- standard error message for memory errors
23local MEMERRMSG = "not enough memory"
24
25
26-- memory error in panic function
27T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
28assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
29T.totalmem(0) -- restore high limit
30
31
32
33-- {==================================================================
34-- Testing memory limits
35-- ===================================================================
36
37checkerr("block too big", T.newuserdata, math.maxinteger)
38collectgarbage()
39local f = load"local a={}; for i=1,100000 do a[i]=i end"
40T.alloccount(10)
41checkerr(MEMERRMSG, f)
42T.alloccount() -- remove limit
43
44
45-- test memory errors; increase limit for maximum memory by steps,
46-- o that we get memory errors in all allocations of a given
47-- task, until there is enough memory to complete the task without
48-- errors.
49local function testbytes (s, f)
50 collectgarbage()
51 local M = T.totalmem()
52 local oldM = M
53 local a,b = nil
54 while true do
55 collectgarbage(); collectgarbage()
56 T.totalmem(M)
57 a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
58 T.totalmem(0) -- remove limit
59 if a and b == "OK" then break end -- stop when no more errors
60 if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
61 error(a, 0) -- propagate it
62 end
63 M = M + 7 -- increase memory limit
64 end
65 print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
66 return a
67end
68
69-- test memory errors; increase limit for number of allocations one
70-- by one, so that we get memory errors in all allocations of a given
71-- task, until there is enough allocations to complete the task without
72-- errors.
73
74local function testalloc (s, f)
75 collectgarbage()
76 local M = 0
77 local a,b = nil
78 while true do
79 collectgarbage(); collectgarbage()
80 T.alloccount(M)
81 a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
82 T.alloccount() -- remove limit
83 if a and b == "OK" then break end -- stop when no more errors
84 if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
85 error(a, 0) -- propagate it
86 end
87 M = M + 1 -- increase allocation limit
88 end
89 print(string.format("minimum allocations for %s: %d allocations", s, M))
90 return a
91end
92
93
94local function testamem (s, f)
95 testalloc(s, f)
96 return testbytes(s, f)
97end
98
99
100-- doing nothing
101b = testamem("doing nothing", function () return 10 end)
102assert(b == 10)
103
104-- testing memory errors when creating a new state
105
106testamem("state creation", function ()
107 local st = T.newstate()
108 if st then T.closestate(st) end -- close new state
109 return st
110end)
111
112testamem("empty-table creation", function ()
113 return {}
114end)
115
116testamem("string creation", function ()
117 return "XXX" .. "YYY"
118end)
119
120testamem("coroutine creation", function()
121 return coroutine.create(print)
122end)
123
124
125-- testing to-be-closed variables
126testamem("to-be-closed variables", function()
127 local flag
128 do
129 local x <close> =
130 setmetatable({}, {__close = function () flag = true end})
131 flag = false
132 local x = {}
133 end
134 return flag
135end)
136
137
138-- testing threads
139
140-- get main thread from registry
141local mt = T.testC("rawgeti R !M; return 1")
142assert(type(mt) == "thread" and coroutine.running() == mt)
143
144
145
146local function expand (n,s)
147 if n==0 then return "" end
148 local e = string.rep("=", n)
149 return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
150 e, s, expand(n-1,s), e)
151end
152
153G=0; collectgarbage(); a =collectgarbage("count")
154load(expand(20,"G=G+1"))()
155assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
156G = nil
157
158testamem("running code on new thread", function ()
159 return T.doonnewstack("local x=1") == 0 -- try to create thread
160end)
161
162
163-- testing memory x compiler
164
165testamem("loadstring", function ()
166 return load("x=1") -- try to do load a string
167end)
168
169
170local testprog = [[
171local function foo () return end
172local t = {"x"}
173AA = "aaa"
174for i = 1, #t do AA = AA .. t[i] end
175return true
176]]
177
178-- testing memory x dofile
179_G.AA = nil
180local t =os.tmpname()
181local f = assert(io.open(t, "w"))
182f:write(testprog)
183f:close()
184testamem("dofile", function ()
185 local a = loadfile(t)
186 return a and a()
187end)
188assert(os.remove(t))
189assert(_G.AA == "aaax")
190
191
192-- other generic tests
193
194testamem("gsub", function ()
195 local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
196 return (a == 'ablo ablo')
197end)
198
199testamem("dump/undump", function ()
200 local a = load(testprog)
201 local b = a and string.dump(a)
202 a = b and load(b)
203 return a and a()
204end)
205
206_G.AA = nil
207
208local t = os.tmpname()
209testamem("file creation", function ()
210 local f = assert(io.open(t, 'w'))
211 assert (not io.open"nomenaoexistente")
212 io.close(f);
213 return not loadfile'nomenaoexistente'
214end)
215assert(os.remove(t))
216
217testamem("table creation", function ()
218 local a, lim = {}, 10
219 for i=1,lim do a[i] = i; a[i..'a'] = {} end
220 return (type(a[lim..'a']) == 'table' and a[lim] == lim)
221end)
222
223testamem("constructors", function ()
224 local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
225 return (type(a) == 'table' and a.e == 5)
226end)
227
228local a = 1
229local close = nil
230testamem("closure creation", function ()
231 function close (b)
232 return function (x) return b + x end
233 end
234 return (close(2)(4) == 6)
235end)
236
237testamem("using coroutines", function ()
238 local a = coroutine.wrap(function ()
239 coroutine.yield(string.rep("a", 10))
240 return {}
241 end)
242 assert(string.len(a()) == 10)
243 return a()
244end)
245
246do -- auxiliary buffer
247 local lim = 100
248 local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
249 testamem("auxiliary buffer", function ()
250 return (#table.concat(a, ",") == 20*lim + lim - 1)
251 end)
252end
253
254testamem("growing stack", function ()
255 local function foo (n)
256 if n == 0 then return 1 else return 1 + foo(n - 1) end
257 end
258 return foo(100)
259end)
260
261-- }==================================================================
262
263
264print "Ok"
265
266
diff --git a/testes/packtests b/testes/packtests
index 0dbb92fe..855c054a 100755
--- a/testes/packtests
+++ b/testes/packtests
@@ -28,6 +28,7 @@ $NAME/literals.lua \
28$NAME/locals.lua \ 28$NAME/locals.lua \
29$NAME/main.lua \ 29$NAME/main.lua \
30$NAME/math.lua \ 30$NAME/math.lua \
31$NAME/memerr.lua \
31$NAME/nextvar.lua \ 32$NAME/nextvar.lua \
32$NAME/pm.lua \ 33$NAME/pm.lua \
33$NAME/sort.lua \ 34$NAME/sort.lua \