Keep memory errors as memory errors

Allow memory errors to be raised through the API (throwing the
error with the memory error message); error in external allocations
raises a memory error; memory errors in coroutines are re-raised
as memory errors.
This commit is contained in:
Roberto Ierusalimschy
2020-07-06 12:09:44 -03:00
parent bfcf06d91a
commit b57574d6fb
4 changed files with 75 additions and 23 deletions

View File

@@ -11,6 +11,9 @@ local debug = require "debug"
local pack = table.pack
-- standard error message for memory errors
local MEMERRMSG = "not enough memory"
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
@@ -408,7 +411,7 @@ do
-- memory error
T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
assert(T.checkpanic("newuserdata 20000") == "not enough memory")
assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
T.totalmem(0) -- restore high limit
-- stack error
@@ -1153,40 +1156,74 @@ do
end
-------------------------------------------------------------------------
-- testing memory limits
-------------------------------------------------------------------------
--[[
** {==================================================================
** Testing memory limits
** ===================================================================
--]]
print("memory-allocation errors")
checkerr("block too big", T.newuserdata, math.maxinteger)
collectgarbage()
local f = load"local a={}; for i=1,100000 do a[i]=i end"
T.alloccount(10)
checkerr("not enough memory", f)
checkerr(MEMERRMSG, f)
T.alloccount() -- remove limit
-- test memory errors; increase limit for maximum memory by steps,
-- o that we get memory errors in all allocations of a given
-- task, until there is enough memory to complete the task without
-- errors.
function testbytes (s, f)
collectgarbage()
local M = T.totalmem()
local oldM = M
local a,b = nil
while true do
collectgarbage(); collectgarbage()
T.totalmem(M)
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
T.totalmem(0) -- remove limit
if a and b == "OK" then break end -- stop when no more errors
if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
error(a, 0) -- propagate it
end
M = M + 7 -- increase memory limit
end
print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
return a
end
-- test memory errors; increase limit for number of allocations one
-- by one, so that we get memory errors in all allocations of a given
-- task, until there is enough allocations to complete the task without
-- errors.
function testamem (s, f)
collectgarbage(); collectgarbage()
function testalloc (s, f)
collectgarbage()
local M = 0
local a,b = nil
while true do
collectgarbage(); collectgarbage()
T.alloccount(M)
a, b = pcall(f)
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
T.alloccount() -- remove limit
if a and b then break end -- stop when no more errors
if not a and not -- `real' error?
(string.find(b, "memory") or string.find(b, "overflow")) then
error(b, 0) -- propagate it
if a and b == "OK" then break end -- stop when no more errors
if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
error(a, 0) -- propagate it
end
M = M + 1 -- increase allocation limit
end
print(string.format("limit for %s: %d allocations", s, M))
return b
print(string.format("minimum allocations for %s: %d allocations", s, M))
return a
end
local function testamem (s, f)
testalloc(s, f)
return testbytes(s, f)
end
@@ -1196,8 +1233,11 @@ assert(b == 10)
-- testing memory errors when creating a new state
b = testamem("state creation", T.newstate)
T.closestate(b); -- close new state
testamem("state creation", function ()
local st = T.newstate()
if st then T.closestate(st) end -- close new state
return st
end)
testamem("empty-table creation", function ()
return {}
@@ -1345,6 +1385,9 @@ testamem("growing stack", function ()
return foo(100)
end)
-- }==================================================================
do -- testing failing in 'lua_checkstack'
local res = T.testC([[rawcheckstack 500000; return 1]])
assert(res == false)