Avoid memory allocation in some functions from 'ltests.c'

To allow their use in memory tests, some functions in 'ltests.c'
should never allocate memory. To avoid this allocation, the
library registers the strings used for status codes, and keeps
the variable '_WARN' always defined (with false instead of nil).
This commit is contained in:
Roberto Ierusalimschy 2020-07-04 16:40:18 -03:00
parent 0280407fc5
commit bfcf06d91a
5 changed files with 30 additions and 17 deletions

View File

@ -121,7 +121,8 @@ static void warnf (void *ud, const char *msg, int tocont) {
strcat(buff, msg); /* add new message to current warning */ strcat(buff, msg); /* add new message to current warning */
if (!tocont) { /* message finished? */ if (!tocont) { /* message finished? */
lua_unlock(L); lua_unlock(L);
if (lua_getglobal(L, "_WARN") == LUA_TNIL) lua_getglobal(L, "_WARN");
if (!lua_toboolean(L, -1))
lua_pop(L, 1); /* ok, no previous unexpected warning */ lua_pop(L, 1); /* ok, no previous unexpected warning */
else { else {
badexit("Unhandled warning in store mode: %s\naborting...\n", badexit("Unhandled warning in store mode: %s\naborting...\n",
@ -1282,10 +1283,19 @@ static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) {
} }
static void pushcode (lua_State *L, int code) { static const char *const statcodes[] = {"OK", "YIELD", "ERRRUN",
static const char *const codes[] = {"OK", "YIELD", "ERRRUN",
"ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"}; "ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"};
lua_pushstring(L, codes[code]);
/*
** Avoid these stat codes from being collected, to avoid possible
** memory error when pushing them.
*/
static void regcodes (lua_State *L) {
unsigned int i;
for (i = 0; i < sizeof(statcodes) / sizeof(statcodes[0]); i++) {
lua_pushboolean(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, statcodes[i]);
}
} }
@ -1508,7 +1518,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
lua_pushnumber(L1, (lua_Number)getnum); lua_pushnumber(L1, (lua_Number)getnum);
} }
else if EQ("pushstatus") { else if EQ("pushstatus") {
pushcode(L1, status); lua_pushstring(L1, statcodes[status]);
} }
else if EQ("pushstring") { else if EQ("pushstring") {
lua_pushstring(L1, getstring); lua_pushstring(L1, getstring);
@ -1710,7 +1720,7 @@ static int Cfunc (lua_State *L) {
static int Cfunck (lua_State *L, int status, lua_KContext ctx) { static int Cfunck (lua_State *L, int status, lua_KContext ctx) {
pushcode(L, status); lua_pushstring(L, statcodes[status]);
lua_setglobal(L, "status"); lua_setglobal(L, "status");
lua_pushinteger(L, ctx); lua_pushinteger(L, ctx);
lua_setglobal(L, "ctx"); lua_setglobal(L, "ctx");
@ -1865,6 +1875,9 @@ int luaB_opentests (lua_State *L) {
void *ud; void *ud;
lua_atpanic(L, &tpanic); lua_atpanic(L, &tpanic);
lua_setwarnf(L, &warnf, L); lua_setwarnf(L, &warnf, L);
lua_pushboolean(L, 0);
lua_setglobal(L, "_WARN"); /* _WARN = false */
regcodes(L);
atexit(checkfinalmem); atexit(checkfinalmem);
lua_assert(lua_getallocf(L, &ud) == debug_realloc); lua_assert(lua_getallocf(L, &ud) == debug_realloc);
lua_assert(ud == cast_voidp(&l_memcontrol)); lua_assert(ud == cast_voidp(&l_memcontrol));

View File

@ -184,7 +184,7 @@ do
if not T then if not T then
warn("@on") warn("@on")
else -- test library else -- test library
assert(string.find(_WARN, "200")); _WARN = nil assert(string.find(_WARN, "200")); _WARN = false
warn("@normal") warn("@normal")
end end
assert(st == false and coroutine.status(co) == "dead" and msg == 111) assert(st == false and coroutine.status(co) == "dead" and msg == 111)

View File

@ -372,7 +372,7 @@ if T then
warn("@on"); warn("@store") warn("@on"); warn("@store")
collectgarbage() collectgarbage()
assert(string.find(_WARN, "error in __gc metamethod")) assert(string.find(_WARN, "error in __gc metamethod"))
assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = nil assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = false
for i = 8, 10 do assert(s[i]) end for i = 8, 10 do assert(s[i]) end
for i = 1, 5 do for i = 1, 5 do
@ -481,7 +481,7 @@ if T then
u = setmetatable({}, {__gc = function () error "@expected error" end}) u = setmetatable({}, {__gc = function () error "@expected error" end})
u = nil u = nil
collectgarbage() collectgarbage()
assert(string.find(_WARN, "@expected error")); _WARN = nil assert(string.find(_WARN, "@expected error")); _WARN = false
warn("@normal") warn("@normal")
end end
@ -657,14 +657,14 @@ if T then
n = n + 1 n = n + 1
assert(n == o[1]) assert(n == o[1])
if n == 1 then if n == 1 then
_WARN = nil _WARN = false
elseif n == 2 then elseif n == 2 then
assert(find(_WARN, "@expected warning")) assert(find(_WARN, "@expected warning"))
lastmsg = _WARN -- get message from previous error (first 'o') lastmsg = _WARN -- get message from previous error (first 'o')
else else
assert(lastmsg == _WARN) -- subsequent error messages are equal assert(lastmsg == _WARN) -- subsequent error messages are equal
end end
warn("@store"); _WARN = nil warn("@store"); _WARN = false
error"@expected warning" error"@expected warning"
end} end}
for i = 10, 1, -1 do for i = 10, 1, -1 do

View File

@ -337,7 +337,7 @@ local function endwarn ()
if not T then if not T then
warn("@on") -- back to normal warn("@on") -- back to normal
else else
assert(_WARN == nil) assert(_WARN == false)
warn("@normal") warn("@normal")
end end
end end
@ -346,7 +346,7 @@ end
local function checkwarn (msg) local function checkwarn (msg)
if T then if T then
assert(string.find(_WARN, msg)) assert(string.find(_WARN, msg))
_WARN = nil -- reset variable to check next warning _WARN = false -- reset variable to check next warning
end end
end end

View File

@ -393,12 +393,12 @@ if T then -- test library?
-- testing 'warn' -- testing 'warn'
warn("@store") warn("@store")
warn("@123", "456", "789") warn("@123", "456", "789")
assert(_WARN == "@123456789"); _WARN = nil assert(_WARN == "@123456789"); _WARN = false
warn("zip", "", " ", "zap") warn("zip", "", " ", "zap")
assert(_WARN == "zip zap"); _WARN = nil assert(_WARN == "zip zap"); _WARN = false
warn("ZIP", "", " ", "ZAP") warn("ZIP", "", " ", "ZAP")
assert(_WARN == "ZIP ZAP"); _WARN = nil assert(_WARN == "ZIP ZAP"); _WARN = false
warn("@normal") warn("@normal")
end end