From bfcf06d91a87b7ffb8c83e290db0cb6176a167f8 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Sat, 4 Jul 2020 16:40:18 -0300 Subject: 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). --- ltests.c | 27 ++++++++++++++++++++------- testes/coroutine.lua | 2 +- testes/gc.lua | 8 ++++---- testes/locals.lua | 4 ++-- testes/main.lua | 6 +++--- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/ltests.c b/ltests.c index 63ad4498..164b5a25 100644 --- a/ltests.c +++ b/ltests.c @@ -121,7 +121,8 @@ static void warnf (void *ud, const char *msg, int tocont) { strcat(buff, msg); /* add new message to current warning */ if (!tocont) { /* message finished? */ 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 */ else { 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 codes[] = {"OK", "YIELD", "ERRRUN", - "ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"}; - lua_pushstring(L, codes[code]); +static const char *const statcodes[] = {"OK", "YIELD", "ERRRUN", + "ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"}; + +/* +** 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); } else if EQ("pushstatus") { - pushcode(L1, status); + lua_pushstring(L1, statcodes[status]); } else if EQ("pushstring") { 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) { - pushcode(L, status); + lua_pushstring(L, statcodes[status]); lua_setglobal(L, "status"); lua_pushinteger(L, ctx); lua_setglobal(L, "ctx"); @@ -1865,6 +1875,9 @@ int luaB_opentests (lua_State *L) { void *ud; lua_atpanic(L, &tpanic); lua_setwarnf(L, &warnf, L); + lua_pushboolean(L, 0); + lua_setglobal(L, "_WARN"); /* _WARN = false */ + regcodes(L); atexit(checkfinalmem); lua_assert(lua_getallocf(L, &ud) == debug_realloc); lua_assert(ud == cast_voidp(&l_memcontrol)); diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 73333c14..0a4c2ef3 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua @@ -184,7 +184,7 @@ do if not T then warn("@on") else -- test library - assert(string.find(_WARN, "200")); _WARN = nil + assert(string.find(_WARN, "200")); _WARN = false warn("@normal") end assert(st == false and coroutine.status(co) == "dead" and msg == 111) diff --git a/testes/gc.lua b/testes/gc.lua index 91915c0b..80850f92 100644 --- a/testes/gc.lua +++ b/testes/gc.lua @@ -372,7 +372,7 @@ if T then warn("@on"); warn("@store") collectgarbage() 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 = 1, 5 do @@ -481,7 +481,7 @@ if T then u = setmetatable({}, {__gc = function () error "@expected error" end}) u = nil collectgarbage() - assert(string.find(_WARN, "@expected error")); _WARN = nil + assert(string.find(_WARN, "@expected error")); _WARN = false warn("@normal") end @@ -657,14 +657,14 @@ if T then n = n + 1 assert(n == o[1]) if n == 1 then - _WARN = nil + _WARN = false elseif n == 2 then assert(find(_WARN, "@expected warning")) lastmsg = _WARN -- get message from previous error (first 'o') else assert(lastmsg == _WARN) -- subsequent error messages are equal end - warn("@store"); _WARN = nil + warn("@store"); _WARN = false error"@expected warning" end} for i = 10, 1, -1 do diff --git a/testes/locals.lua b/testes/locals.lua index 0e5e0c74..f5e96244 100644 --- a/testes/locals.lua +++ b/testes/locals.lua @@ -337,7 +337,7 @@ local function endwarn () if not T then warn("@on") -- back to normal else - assert(_WARN == nil) + assert(_WARN == false) warn("@normal") end end @@ -346,7 +346,7 @@ end local function checkwarn (msg) if T then assert(string.find(_WARN, msg)) - _WARN = nil -- reset variable to check next warning + _WARN = false -- reset variable to check next warning end end diff --git a/testes/main.lua b/testes/main.lua index de14a088..d2d602de 100644 --- a/testes/main.lua +++ b/testes/main.lua @@ -393,12 +393,12 @@ if T then -- test library? -- testing 'warn' warn("@store") warn("@123", "456", "789") - assert(_WARN == "@123456789"); _WARN = nil + assert(_WARN == "@123456789"); _WARN = false warn("zip", "", " ", "zap") - assert(_WARN == "zip zap"); _WARN = nil + assert(_WARN == "zip zap"); _WARN = false warn("ZIP", "", " ", "ZAP") - assert(_WARN == "ZIP ZAP"); _WARN = nil + assert(_WARN == "ZIP ZAP"); _WARN = false warn("@normal") end -- cgit v1.2.3-55-g6feb