From 72e441132f8a06679228b5f19e852f842b44689b Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Mon, 20 Aug 2012 18:37:42 +0100 Subject: TPT: Prevent accidental infinite loops in lua, fixes #115 diff --git a/src/cat/LuaScriptHelper.h b/src/cat/LuaScriptHelper.h index 8b2d9fa..d2174ea 100644 --- a/src/cat/LuaScriptHelper.h +++ b/src/cat/LuaScriptHelper.h @@ -30,6 +30,7 @@ int tptPropertiesVersion; int tptElements; //Table for TPT element names int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, tptPart, cIndex; +void luacon_hook(lua_State *L, lua_Debug *ar); int luacon_step(int mx, int my, int selectl, int selectr, int bsx, int bsy); int luacon_mouseevent(int mx, int my, int mb, int event, int mouse_wheel); int luacon_keyevent(int key, int modifier, int event); diff --git a/src/cat/LuaScriptInterface.cpp b/src/cat/LuaScriptInterface.cpp index a338802..95573a0 100644 --- a/src/cat/LuaScriptInterface.cpp +++ b/src/cat/LuaScriptInterface.cpp @@ -25,6 +25,7 @@ #else #include #endif + #include LuaScriptInterface::LuaScriptInterface(GameModel * m): CommandInterface(m), @@ -141,6 +142,7 @@ LuaScriptInterface::LuaScriptInterface(GameModel * m): lua_setfield(l, tptPropertiesVersion, "build"); lua_setfield(l, tptProperties, "version"); + lua_sethook(l, &luacon_hook, LUA_MASKCOUNT, 200); #ifdef FFI //LuaJIT's ffi gives us direct access to parts data, no need for nested metatables. HOWEVER, this is in no way safe, it's entirely possible for someone to try to read parts[-10] lua_pushlightuserdata(l, parts); @@ -300,6 +302,7 @@ bool LuaScriptInterface::OnKeyRelease(int key, Uint16 character, bool shift, boo void LuaScriptInterface::OnTick() { + LoopTime = clock(); if(luacon_mousedown) luacon_mouseevent(luacon_mousex, luacon_mousey, luacon_mousebutton, LUACON_MPRESS, 0); luacon_step(luacon_mousex, luacon_mousey, luacon_selectedl, luacon_selectedr, luacon_brushx, luacon_brushy); @@ -319,6 +322,7 @@ int LuaScriptInterface::Command(std::string command) int ret; lastError = ""; currentCommand = true; + LoopTime = clock(); if((ret = luaL_dostring(l, command.c_str()))) { lastError = luacon_geterror(); @@ -874,28 +878,42 @@ int luacon_step(int mx, int my, int selectl, int selectr, int bsx, int bsy){ lua_setfield(luacon_ci->l, tptProperties, "selectedr"); lua_setfield(luacon_ci->l, tptProperties, "brushx"); lua_setfield(luacon_ci->l, tptProperties, "brushy"); - if(step_functions[0]){ - //Set mouse globals - for(i = 0; i<6; i++){ - if(step_functions[i]){ - lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, step_functions[i]); - callret = lua_pcall(luacon_ci->l, 0, 0, 0); - if (callret) + for(i = 0; i<6; i++){ + if(step_functions[i]){ + lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, step_functions[i]); + callret = lua_pcall(luacon_ci->l, 0, 0, 0); + if (callret) + { + if (!strcmp(luacon_geterror(),"Error: Script not responding")) { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); + luacon_ci->LoopTime = clock(); + lua_pushcfunction(luacon_ci->l, &luatpt_unregister_step); + lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, step_functions[i]); + lua_pcall(luacon_ci->l, 1, 0, 0); } + luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); } } - return tempret; } return 0; } int luacon_eval(char *command){ + luacon_ci->LoopTime = clock(); return luaL_dostring (luacon_ci->l, command); } +void luacon_hook(lua_State * l, lua_Debug * ar) +{ + if(ar->event == LUA_HOOKCOUNT && clock()-luacon_ci->LoopTime > CLOCKS_PER_SEC*3) + { + if(ConfirmPrompt::Blocking("Script not responding", "The Lua script may have stopped responding. There might be an infinite loop. Press \"Stop\" to stop it", "Stop")) + luaL_error(l, "Error: Script not responding"); + luacon_ci->LoopTime = clock(); + } +} + char *luacon_geterror(){ char *error = (char*)lua_tostring(luacon_ci->l, -1); if(error==NULL || !error[0]){ diff --git a/src/cat/LuaScriptInterface.h b/src/cat/LuaScriptInterface.h index 44ad279..8c3e33e 100644 --- a/src/cat/LuaScriptInterface.h +++ b/src/cat/LuaScriptInterface.h @@ -40,6 +40,7 @@ class LuaScriptInterface: public CommandInterface { bool currentCommand; TPTScriptInterface * legacy; public: + int LoopTime; lua_State *l; LuaScriptInterface(GameModel * m); virtual bool OnBrushChanged(int brushType, int rx, int ry); -- cgit v0.9.2-21-gd62e