mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-10 23:02:03 +00:00
Lunatic: make baselib functions used in defs.c local, be more disciplined with stack.
Also, print a backtrace if we return to C with an error. git-svn-id: https://svn.eduke32.com/eduke32@2827 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
420e61d0f8
commit
b86dbc0818
3 changed files with 97 additions and 37 deletions
|
@ -504,7 +504,11 @@ end
|
|||
|
||||
-- _G tweaks -- pull in only 'safe' stuff
|
||||
local G_ = {} -- our soon-to-be global environment
|
||||
local oG = _G -- old genv, to access thrown-out functions later in this chunk
|
||||
|
||||
-- Old global environment, to access thrown-out functions later in this chunk.
|
||||
-- Also, inside this file, we must refer to functions like 'pairs' by using
|
||||
-- this table, since user code could later do pairs=nil.
|
||||
local oG = _G
|
||||
|
||||
G_.coroutine = coroutine
|
||||
G_.assert = assert
|
||||
|
@ -565,16 +569,25 @@ local lunacon = require("lunacon")
|
|||
|
||||
|
||||
-- change the environment of this chunk to the table G_
|
||||
-- NOTE: all references to global variables from this point on
|
||||
-- (also in functions created after this point) refer to G_ !
|
||||
setfenv(1, G_)
|
||||
|
||||
-- We MUST remember to call base lib functions through oG here.
|
||||
-- 'tostring' is a special case: it is used in 'print', i.e. the global 'tostring',
|
||||
-- which is looked up in the current environment! Thus, we must REMOVE it and
|
||||
-- 'print' for release, or write our own, atomic 'print'.
|
||||
local error = oG.error
|
||||
local type = oG.type
|
||||
local pairs = oG.pairs
|
||||
|
||||
-- print keys and values of a table
|
||||
local function printkv(label, table)
|
||||
print('========== Keys and values of '..label)
|
||||
for k,v in pairs(table) do
|
||||
print(k .. ': ' .. tostring(v))
|
||||
oG.print('========== Keys and values of '..label)
|
||||
for k,v in oG.pairs(table) do
|
||||
oG.print(k .. ': ' .. tostring(v))
|
||||
end
|
||||
print('----------')
|
||||
oG.print('----------')
|
||||
end
|
||||
|
||||
--printkv('_G AFTER SETFENV', _G)
|
||||
|
@ -854,7 +867,7 @@ local function loadGamevarsString(string)
|
|||
gamevarNames = {}; -- clear gamevars
|
||||
--]=]
|
||||
|
||||
assert(oG.loadstring(string))()
|
||||
oG.assert(oG.loadstring(string))()
|
||||
end
|
||||
|
||||
|
||||
|
@ -876,11 +889,11 @@ DBG_.loadGamevarsString = loadGamevarsString
|
|||
-- XXX: but user modules will want to do "function thisfunc() ... "
|
||||
oG.setmetatable(
|
||||
G_, {
|
||||
__newindex = function (_, n)
|
||||
error("attempt to write to undeclared variable "..n, 2)
|
||||
__newindex = function (_1, n, _2)
|
||||
error("attempt to write to undeclared variable '"..n.."'", 2)
|
||||
end,
|
||||
__index = function (_, n)
|
||||
error("attempt to read undeclared variable "..n, 2)
|
||||
error("attempt to read undeclared variable '"..n.."'", 2)
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ uint8_t g_elEvents[MAXEVENTS];
|
|||
// same thing for actors:
|
||||
uint8_t g_elActors[MAXTILES];
|
||||
|
||||
// Lua-registry key for debug.traceback
|
||||
static uint8_t debug_traceback_key;
|
||||
|
||||
|
||||
// forward-decls...
|
||||
static int32_t SetEvent_luacf(lua_State *L);
|
||||
|
@ -29,14 +32,27 @@ static int32_t SetActor_luacf(lua_State *L);
|
|||
extern int luaopen_lpeg(lua_State *L);
|
||||
|
||||
|
||||
static void check_and_register_function(lua_State *L, void *keyaddr)
|
||||
{
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
|
||||
lua_pushlightuserdata(L, keyaddr); // 3, push address
|
||||
lua_pushvalue(L, -2); // 4, push copy of lua function
|
||||
|
||||
lua_settable(L, LUA_REGISTRYINDEX); // "registry[keyaddr] = <lua function>", pop 2
|
||||
}
|
||||
|
||||
|
||||
// 0: success, <0: failure
|
||||
int32_t El_CreateState(El_State *estate, const char *name)
|
||||
{
|
||||
lua_State *L;
|
||||
|
||||
estate->name = Bstrdup(name);
|
||||
if (!estate->name)
|
||||
return -1;
|
||||
|
||||
estate->L = luaL_newstate();
|
||||
L = estate->L = luaL_newstate();
|
||||
|
||||
if (!estate->L)
|
||||
{
|
||||
|
@ -45,14 +61,24 @@ int32_t El_CreateState(El_State *estate, const char *name)
|
|||
return -2;
|
||||
}
|
||||
|
||||
luaL_openlibs(estate->L); // NOTE: we set up the sandbox in defs.ilua
|
||||
luaopen_lpeg(estate->L);
|
||||
luaL_openlibs(L); // NOTE: we set up the sandbox in defs.ilua
|
||||
luaopen_lpeg(L);
|
||||
lua_pop(L, lua_gettop(L)); // pop off whatever lpeg leaves on the stack
|
||||
|
||||
// get debug.traceback
|
||||
lua_getglobal(L, "debug");
|
||||
lua_getfield(L, -1, "traceback");
|
||||
Bassert(lua_isfunction(L, -1));
|
||||
check_and_register_function(L, &debug_traceback_key);
|
||||
lua_pop(L, 2);
|
||||
|
||||
// create misc. global functions in the Lua state
|
||||
lua_pushcfunction(estate->L, SetEvent_luacf);
|
||||
lua_setglobal(estate->L, "gameevent");
|
||||
lua_pushcfunction(estate->L, SetActor_luacf);
|
||||
lua_setglobal(estate->L, "gameactor");
|
||||
lua_pushcfunction(L, SetEvent_luacf);
|
||||
lua_setglobal(L, "gameevent");
|
||||
lua_pushcfunction(L, SetActor_luacf);
|
||||
lua_setglobal(L, "gameactor");
|
||||
|
||||
Bassert(lua_gettop(L)==0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,57 +136,69 @@ int32_t El_RunOnce(El_State *estate, const char *fn)
|
|||
buf[flen] = 0;
|
||||
|
||||
// -- lua --
|
||||
Bassert(lua_gettop(L)==0);
|
||||
|
||||
// get debug.traceback
|
||||
lua_pushlightuserdata(L, &debug_traceback_key);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
Bassert(lua_isfunction(L, -1));
|
||||
|
||||
i = luaL_loadstring(L, buf);
|
||||
Bassert(lua_gettop(L)==2);
|
||||
Bfree(buf);
|
||||
|
||||
if (i == LUA_ERRMEM)
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == LUA_ERRSYNTAX)
|
||||
{
|
||||
OSD_Printf("state \"%s\" syntax error: %s\n", estate->name,
|
||||
lua_tostring(L, -1)); // get err msg
|
||||
lua_pop(L, 1);
|
||||
lua_pop(L, 2); // pop errmsg and debug.traceback
|
||||
return 3;
|
||||
}
|
||||
|
||||
// -- call the lua chunk! --
|
||||
|
||||
i = lua_pcall(L, 0, 0, 0);
|
||||
i = lua_pcall(L, 0, 0, -2);
|
||||
Bassert(lua_gettop(L) == 1+!!i);
|
||||
Bassert(i != LUA_ERRERR); // we expect debug.traceback not to fail
|
||||
|
||||
if (i == LUA_ERRMEM) // XXX: should be more sophisticated. Clean up stack? Do GC?
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == LUA_ERRRUN)
|
||||
{
|
||||
Bassert(lua_type(L, -1)==LUA_TSTRING);
|
||||
OSD_Printf("state \"%s\" runtime error: %s\n", estate->name,
|
||||
lua_tostring(L, -1)); // get err msg
|
||||
lua_pop(L, 1);
|
||||
lua_pop(L, 2); // pop errmsg and debug.traceback
|
||||
return 4;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void check_and_register_function(lua_State *L, void *keyaddr)
|
||||
{
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
lua_pushlightuserdata(L, keyaddr); // 3, push address
|
||||
lua_pushvalue(L, 2); // 4, push copy of lua function
|
||||
|
||||
lua_settable(L, LUA_REGISTRYINDEX); // "registry[keyaddr] = <lua function>"
|
||||
}
|
||||
|
||||
|
||||
////////// Lua_CFunctions //////////
|
||||
|
||||
// gameevent(EVENT_..., lua_function)
|
||||
static int32_t SetEvent_luacf(lua_State *L)
|
||||
{
|
||||
int32_t eventidx = luaL_checkint(L, 1);
|
||||
int32_t eventidx;
|
||||
|
||||
if (lua_gettop(L) != 2)
|
||||
luaL_error(L, "gameevent: must pass exactly two arguments");
|
||||
|
||||
eventidx = luaL_checkint(L, 1);
|
||||
|
||||
luaL_argcheck(L, (unsigned)eventidx < MAXEVENTS, 1, "must be an event number (0 .. MAXEVENTS-1)");
|
||||
check_and_register_function(L, &g_elEvents[eventidx]);
|
||||
|
@ -172,7 +210,12 @@ static int32_t SetEvent_luacf(lua_State *L)
|
|||
// gameactor(<actortile>, lua_function)
|
||||
static int32_t SetActor_luacf(lua_State *L)
|
||||
{
|
||||
int32_t actortile = luaL_checkint(L, 1);
|
||||
int32_t actortile;
|
||||
|
||||
if (lua_gettop(L) != 2)
|
||||
luaL_error(L, "gameactor: must pass exactly two arguments");
|
||||
|
||||
actortile = luaL_checkint(L, 1);
|
||||
|
||||
luaL_argcheck(L, (unsigned)actortile < MAXTILES, 1, "must be an tile number (0 .. MAXTILES-1)");
|
||||
check_and_register_function(L, &g_elActors[actortile]);
|
||||
|
@ -188,8 +231,9 @@ static int32_t call_registered_function3(lua_State *L, void *keyaddr,
|
|||
{
|
||||
int32_t i;
|
||||
|
||||
lua_pushlightuserdata(L, keyaddr); // push address
|
||||
lua_gettable(L, LUA_REGISTRYINDEX); // get lua function
|
||||
// get the Lua function from the registry
|
||||
lua_pushlightuserdata(L, keyaddr);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
|
||||
lua_pushinteger(L, iActor);
|
||||
lua_pushinteger(L, iPlayer);
|
||||
|
@ -200,6 +244,7 @@ static int32_t call_registered_function3(lua_State *L, void *keyaddr,
|
|||
i = lua_pcall(L, 3, 0, 0);
|
||||
if (i == LUA_ERRMEM)
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
// XXX: should be more sophisticated. Clean up stack? Do GC?
|
||||
}
|
||||
|
||||
|
|
|
@ -89,10 +89,12 @@ if (vol==1 and lev==8) then
|
|||
end
|
||||
|
||||
--]]
|
||||
--tostring = nil -- REMEMBER
|
||||
--DBG_.printkv('_G in test.elua', _G)
|
||||
|
||||
checkfail('local i = sprite["qwe"]') -- indexing struct array with non-numeric type
|
||||
checkfail('print(sprite[100000].ceilingpal)') -- oob read access
|
||||
checkfail('print(gv.sprite[0])') -- NOTE: gv.sprite doesn't fail, but we can't use it
|
||||
checkfail('setmetatable(sprite, {})') -- set metatable forbidden
|
||||
checkfail('sector[-1].ceilingpal = 4') -- oob write access
|
||||
checkfail('sector[0].wallnum = 0') -- wallnum member is read-only
|
||||
|
@ -114,8 +116,10 @@ checkfail('string.dump(gameevent)') -- string.dump is unavailable
|
|||
checkfail('gv.luaJIT_setmode(nil, 0, 0)')
|
||||
checkfail('gv.luaJIT_BC_con_lang')
|
||||
checkfail('gv.yax_getbunch(0,0)')
|
||||
checkfail('gv.gethitickms = nil')
|
||||
-- we don't have arrays in Lua-accessible structs now
|
||||
checkfail('local i = actor[0].t_data[15]')
|
||||
checkfail('local spr = sprite[0]; local x=spr+1') -- no pointer arithmetic!
|
||||
|
||||
printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING))
|
||||
|
||||
|
@ -138,7 +142,7 @@ gameevent(gv.EVENT_ENTERLEVEL,
|
|||
|
||||
t = gv.gethitickms()-t
|
||||
|
||||
-- x86: 40ns/call, x86_64: 290 ns/call
|
||||
-- x86_64: 40ns/call, x86: 290 ns/call
|
||||
printf("%d gethitickms() calls took %.03f ms (%.03f us/call)",
|
||||
N, t, (t*1000)/N)
|
||||
|
||||
|
@ -169,8 +173,6 @@ gameactor(1680, -- LIZTROOP
|
|||
-- sprite[i].ang = bit.band(sprite[i].ang-20, 2047)
|
||||
|
||||
local spr = sprite[i]
|
||||
-- print(type(spr)) --> cdata
|
||||
assert(pcall("print(spr+1)") == false) -- no ptr arith!
|
||||
|
||||
local x,y,z = spr.x, spr.y, spr.z
|
||||
local t = gv.gethitickms()
|
||||
|
|
Loading…
Reference in a new issue