static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ lua_sethook(L, NULL, 0, 0); luaL_error(L, "interrupted!"); }
static void laction(int i) { signal(i, SIG_DFL); lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); }
void LuaHostWindows::DetachLuaHook( lua_State* lvm, lua_Hook hook ) { lua_sethook(lvm, NULL, 0, 0); }
UINT CLuaInterpreter::ProcThreadExec(HANDLE hEventStop) { static char szFunc[] = "CLuaInterpreter::ProcThreadExec"; CMainFrame* pMainFrame = (CMainFrame*)theApp.m_pMainWnd; m_bStop = false; // Initialisation LUA m_LuaState = lua_open(); if (m_LuaState == NULL) { ADE_ERROR("Unable to initialize LUA"); } else { // on indique que l'execution commence m_bIsRunning = true; // On se lit au manager (afin de pouvoir être notifié si une deconnection intervient) CLuaInterpreterMgr::ReadSingleInstance()->NotifyStartOfExec(this); lua_gc(m_LuaState, LUA_GCSTOP, 0); /* stop collector during initialization */ luaL_openlibs(m_LuaState); /* open libraries */ ITFLUA_open(m_LuaState); // Puis on ouvre les autres DLL CLuaDllMgr::ReadSingleInstance()->OpenLibs(m_LuaState); lua_gc(m_LuaState, LUA_GCRESTART, 0); int ret; if (m_Code.size()) { // chargement depuis un buffer ret = luaL_loadbuffer(m_LuaState, m_Code.c_str(), m_Code.size(), m_CodeName.c_str()); } else { // chargement depuis un fichier ret = luaL_loadfile(m_LuaState, m_FileName.c_str()); } if (ret != 0) { const char* e = lua_tostring(m_LuaState, -1); if (e == NULL) { char szTmp[] = "LUA: Unknown error in luaL_loadbuffer"; pMainFrame->SendToTraceWindow(szTmp, CTraceBar::LUA_TRACE); } else { pMainFrame->SendToTraceWindow((char*)e, CTraceBar::LUA_TRACE); } } else { m_LuaState->user_param = (void *)this; lua_sethook(m_LuaState, hook, LUA_MASKLINE | LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); ret = lua_pcall(m_LuaState, 0, 0, 0); if (ret != 0) { const char* e = lua_tostring(m_LuaState, -1); if (e == NULL) { char szTmp[] = "LUA: Unknown error in lua_pcall"; pMainFrame->SendToTraceWindow(szTmp, CTraceBar::LUA_TRACE); } else { #if 1 pMainFrame->SendToTraceWindow((char*)e, CTraceBar::LUA_TRACE); #else const char* halt = "HALT: "; bool is_halt = true; for (int i = 0; i < 6 && is_halt; ++i) if (halt[i] != e[i]) is_halt = false; if (is_halt) m_ErrorMessage = e; else m_ErrorMessage.Format("ERROR: %s", e); #endif } } } // puis on ferme tout lua_close(m_LuaState); ITFLUA_close(); CLuaDllMgr::ReadSingleInstance()->CloseLibs(); // On indique que l'exec est finie avant de faire le NotifyEndOfExec // car : 1. dans CLuaInterpreter::NotifyDisconnect on fait une attente actif jusqu'à voir // m_bIsRunning = false // 2. le thread, lorqu'il va appelé NotifyEndOfExec risque d'être bloqué sur l'attente // de section critique (peut-être prise par CLuaInterpreterMgr::NotifyDisconnect) donc il faut // mettre a jour m_bIsRunning avant pour éviter un deadlock m_bIsRunning = false; // On supprime le lien avec le manager CLuaInterpreterMgr::ReadSingleInstance()->NotifyEndOfExec(this); } m_bIsRunning = false; // et on notifie la fin if (m_pNotificationCallback) { m_pNotificationCallback(m_lpParam, EVT_END); } return 0; }
static void stop_hook(lua_State *lua, lua_Debug *ar) { (void)ar; /* unused arg. */ lua_sethook(lua, NULL, 0, 0); luaL_error(lua, LSB_SHUTTING_DOWN); }
static lua_State* luastate_New(int (*terminationCallback)(void* stateptr)) { lua_State* l = luaL_newstate(); lua_gc(l, LUA_GCSTOP, 0); //lua_gc(l, LUA_GCSETPAUSE, 110); //lua_gc(l, LUA_GCSETSTEPMUL, 300); if (terminationCallback) { // allow possible script kill when script runs too long: lua_sethook(l, &luastate_InstructionCallback, LUA_MASKCOUNT, 5000); // push the pointer to the lua registry: lua_pushstring(l, "terminationCallback"); lua_pushlightuserdata(l, (void*)terminationCallback); lua_settable(l, LUA_REGISTRYINDEX); } // standard libs luaL_openlibs(l); luastate_RememberTracebackFunc(l); luastate_VoidDebug(l); luastate_AddBlitwizFuncs(l); // clean up global namespace apart from whitelist: luastate_ApplyWhitelist(l); // own dofile/loadfile/print lua_pushcfunction(l, &luafuncs_loadfile); lua_setglobal(l, "loadfile"); lua_pushcfunction(l, &luafuncs_dofile); lua_setglobal(l, "dofile"); lua_pushcfunction(l, &luafuncs_print); lua_setglobal(l, "print"); lua_pushcfunction(l, &luafuncs_dostring); lua_setglobal(l, "dostring"); lua_pushcfunction(l, &luafuncs_dostring_returnvalues); lua_setglobal(l, "dostring_returnvalues"); // obtain the blitwiz lib lua_getglobal(l, "blitwizard"); // blitwizard.runDelayed: lua_pushstring(l, "runDelayed"); lua_pushcfunction(l, &luafuncs_runDelayed); lua_settable(l, -3); // blitwizard.object: lua_pushstring(l, "object"); luastate_CreateObjectTable(l); lua_settable(l, -3); // blitwizard.getAllObjects(): lua_pushstring(l, "getAllObjects"); lua_pushcfunction(l, &luafuncs_getAllObjects); lua_settable(l, -3); // blitwizard.scanFor2dObjects(): lua_pushstring(l, "scanFor2dObjects"); lua_pushcfunction(l, &luafuncs_scanFor2dObjects); lua_settable(l, -3); // blitwizard.setStep: lua_pushstring(l, "setStep"); lua_pushcfunction(l, &luafuncs_setstep); lua_settable(l, -3); // blitwizard.loadResourceArchive lua_pushstring(l, "loadResourceArchive"); lua_pushcfunction(l, &luafuncs_loadResourceArchive); lua_settable(l, -3); // blitwizard.getTemplateDirectory: lua_pushstring(l, "getTemplateDirectory"); lua_pushcfunction(l, &luafuncs_getTemplateDirectory); lua_settable(l, -3); // blitwizard namespaces lua_pushstring(l, "graphics"); luastate_CreateGraphicsTable(l); lua_settable(l, -3); lua_pushstring(l, "net"); luastate_CreateNetTable(l); lua_settable(l, -3); lua_pushstring(l, "audio"); luastate_CreateAudioTable(l); lua_settable(l, -3); lua_pushstring(l, "debug"); luastate_CreateDebugTable(l); lua_settable(l, -3); lua_pushstring(l, "callback"); lua_newtable(l); lua_pushstring(l, "event"); lua_newtable(l); lua_settable(l, -3); lua_settable(l, -3); lua_pushstring(l, "time"); luastate_CreateTimeTable(l); lua_settable(l, -3); lua_pushstring(l, "physics"); luastate_CreatePhysicsTable(l); lua_settable(l, -3); // we still have the module "blitwiz" on the stack here lua_pop(l, 1); // vector namespace: luastate_CreateVectorTable(l); lua_setglobal(l, "vector"); // obtain math table lua_getglobal(l, "math"); // math namespace extensions lua_pushstring(l, "trandom"); lua_pushcfunction(l, &luafuncs_trandom); lua_settable(l, -3); // remove math table from stack lua_pop(l, 1); // obtain os table lua_getglobal(l, "os"); // os namespace extensions lua_pushstring(l, "exit"); lua_pushcfunction(l, &luafuncs_exit); lua_settable(l, -3); lua_pushstring(l, "chdir"); lua_pushcfunction(l, &luafuncs_chdir); lua_settable(l, -3); lua_pushstring(l, "templatedir"); lua_pushcfunction(l, &luafuncs_templatedir); lua_settable(l, -3); lua_pushstring(l, "sleep"); lua_pushcfunction(l, &luafuncs_sleep); lua_settable(l, -3); lua_pushstring(l, "gameluapath"); lua_pushcfunction(l, &luafuncs_gameluapath); lua_settable(l, -3); lua_pushstring(l, "forcetemplatedir"); lua_pushcfunction(l, &luafuncs_forcetemplatedir); lua_settable(l, -3); lua_pushstring(l, "openConsole"); lua_pushcfunction(l, &luafuncs_openConsole); lua_settable(l, -3); lua_pushstring(l, "ls"); lua_pushcfunction(l, &luafuncs_ls); lua_settable(l, -3); lua_pushstring(l, "isdir"); lua_pushcfunction(l, &luafuncs_isdir); lua_settable(l, -3); lua_pushstring(l, "getcwd"); lua_pushcfunction(l, &luafuncs_getcwd); lua_settable(l, -3); lua_pushstring(l, "exists"); lua_pushcfunction(l, &luafuncs_exists); lua_settable(l, -3); lua_pushstring(l, "sysname"); lua_pushcfunction(l, &luafuncs_sysname); lua_settable(l, -3); lua_pushstring(l, "sysversion"); lua_pushcfunction(l, &luafuncs_sysversion); lua_settable(l, -3); // throw table "os" off the stack lua_pop(l, 1); // get "string" table for custom string functions lua_getglobal(l, "string"); // set custom string functions lua_pushstring(l, "startswith"); lua_pushcfunction(l, &luafuncs_startswith); lua_settable(l, -3); lua_pushstring(l, "endswith"); lua_pushcfunction(l, &luafuncs_endswith); lua_settable(l, -3); lua_pushstring(l, "split"); lua_pushcfunction(l, &luafuncs_split); lua_settable(l, -3); // throw table "string" off the stack lua_pop(l, 1); // set _VERSION string: char vstr[512]; char is64bit[] = " (64-bit binary)"; #ifndef _64BIT strcpy(is64bit, ""); #endif snprintf(vstr, sizeof(vstr), "Blitwizard %s based on Lua 5.2%s", VERSION, is64bit); lua_pushstring(l, vstr); lua_setglobal(l, "_VERSION"); // now set a default blitwizard.onLog handler: lua_getglobal(l, "dostring"); lua_pushstring(l, "function blitwizard.onLog(type, msg)\n" " print(\"[LOG:\" .. type .. \"] \" .. msg)\n" "end\n"); // coverity[unchecked_value] - we don't want to cause error message // logs from logging itself since that could cause an infinite loop. // therefore, we don't handle possible lua errors here. lua_pcall(l, 1, 0, 0); return l; }
static void laction(int i) { signal(i, G.PluginData.old_action); lua_sethook(G.LS, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); }
static void sig_postpone (int i) { signalno = i; lua_sethook(signalL, sig_handle, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); }
int aura_setup_vm_protection(lua_State *L, int cnt) { count = cnt; lua_sethook (L, handle_runaway, LUA_MASKCOUNT, count); return 0; }
void evalGenericCommand(redisClient *c, int evalsha) { lua_State *lua = server.lua; char funcname[43]; long long numkeys; int delhook = 0; /* We want the same PRNG sequence at every call so that our PRNG is * not affected by external state. * * 在每次执行 EVAL 时重置随机 seed ,从而保证可以生成相同的随机序列。 */ redisSrand48(0); /* We set this flag to zero to remember that so far no random command * was called. This way we can allow the user to call commands like * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command * is called (otherwise the replication and AOF would end with non * deterministic sequences). * * Thanks to this flag we'll raise an error every time a write command * is called after a random command was used. * * 用两个变量,对命令进行检查 * 确保在调用随机命令之后,再调用写命令将出现错误 */ server.lua_random_dirty = 0; server.lua_write_dirty = 0; /* Get the number of arguments that are keys */ // 获取输入键的数量 if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != REDIS_OK) return; // 对键的正确性做一个快速检查 if (numkeys > (c->argc - 3)) { addReplyError(c,"Number of keys can't be greater than number of args"); return; } /* We obtain the script SHA1, then check if this function is already * defined into the Lua state */ // 组合出函数的名字,例如 f_282297a0228f48cd3fc6a55de6316f31422f5d17 funcname[0] = 'f'; funcname[1] = '_'; if (!evalsha) { /* Hash the code if this is an EVAL call */ // 如果执行的是 EVAL 命令,那么计算脚本的 SHA1 校验和 sha1hex(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr)); } else { // 如果执行的是 EVALSHA 命令,直接使用传入的 SHA1 值 /* We already have the SHA if it is a EVALSHA */ int j; char *sha = c->argv[1]->ptr; for (j = 0; j < 40; j++) funcname[j+2] = tolower(sha[j]); funcname[42] = '\0'; } /* Try to lookup the Lua function */ // 按名查找函数 lua_getglobal(lua, funcname); if (lua_isnil(lua,1)) { // 没找到脚本相应的脚本 lua_pop(lua,1); /* remove the nil from the stack */ /* Function not defined... let's define it if we have the * body of the funciton. If this is an EVALSHA call we can just * return an error. */ if (evalsha) { // 如果执行的是 EVALSHA ,返回脚本未找到错误 addReply(c, shared.noscripterr); return; } // 如果执行的是 EVAL ,那么创建并执行新函数,然后将代码添加到脚本字典中 if (luaCreateFunction(c,lua,funcname,c->argv[1]) == REDIS_ERR) return; /* Now the following is guaranteed to return non nil */ lua_getglobal(lua, funcname); redisAssert(!lua_isnil(lua,1)); } /* Populate the argv and keys table accordingly to the arguments that * EVAL received. */ // 设置 KEYS 和 ARGV 全局变量到 Lua 环境 luaSetGlobalArray(lua,"KEYS",c->argv+3,numkeys); luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argc-3-numkeys); /* Select the right DB in the context of the Lua client */ // 为 Lua 所属的(伪)客户端设置数据库 selectDb(server.lua_client,c->db->id); /* Set an hook in order to be able to stop the script execution if it * is running for too much time. * * 设置一个钩子,用于在运行时间过长时停止脚本的运作。 * * We set the hook only if the time limit is enabled as the hook will * make the Lua script execution slower. * * 只在开启了时间限制选项时使用钩子,因为它会拖慢脚本的运行速度。 */ // 调用客户端 server.lua_caller = c; // 脚本开始时间 server.lua_time_start = ustime()/1000; // 是否杀死脚本 server.lua_kill = 0; // 只在开启时间限制时使用钩子 if (server.lua_time_limit > 0 && server.masterhost == NULL) { lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000); delhook = 1; } /* At this point whatever this script was never seen before or if it was * already defined, we can call it. We have zero arguments and expect * a single return value. */ // 执行脚本(所属的函数) if (lua_pcall(lua,0,1,0)) { // 以下是脚本执行出错的代码。。。 // 删除钩子 if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */ // 脚本执行已超时 if (server.lua_timedout) { // 清除超时 FLAG server.lua_timedout = 0; /* Restore the readable handler that was unregistered when the * script timeout was detected. */ // 将超时钩子里删除的读事件重新加上 aeCreateFileEvent(server.el,c->fd,AE_READABLE, readQueryFromClient,c); } // 清空调用者 server.lua_caller = NULL; // 更新目标数据库 selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */ addReplyErrorFormat(c,"Error running script (call to %s): %s\n", funcname, lua_tostring(lua,-1)); // 弹出函数 lua_pop(lua,1); // 执行完整的废料回首循环(full garbage-collection cycle) lua_gc(lua,LUA_GCCOLLECT,0); // 返回 return; } // 以下是脚本执行成功时执行的代码。。。 // 删除钩子 if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */ // 清空超时 FLAG server.lua_timedout = 0; // 清空调用者 server.lua_caller = NULL; // 更新 DB selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */ // 将 Lua 回复转换成 Redis 回复 luaReplyToRedisReply(c,lua); // 执行 1 步渐进式 GC lua_gc(lua,LUA_GCSTEP,1); /* If we have slaves attached we want to replicate this command as * EVAL instead of EVALSHA. We do this also in the AOF as currently there * is no easy way to propagate a command in a different way in the AOF * and in the replication link. * * 如果有附属节点,那么使用 EVAL 而不是 EVALSHA 来传播脚本 * 因为目前还没有代码可以检测脚本是否已经传送到附属节点中 * * IMPROVEMENT POSSIBLE: * 1) Replicate this command as EVALSHA in the AOF. * 2) Remember what slave already received a given script, and replicate * the EVALSHA against this slaves when possible. */ // 如果执行的是 EVALSHA 命令 if (evalsha) { // 取出脚本代码体(body) robj *script = dictFetchValue(server.lua_scripts,c->argv[1]->ptr); redisAssertWithInfo(c,NULL,script != NULL); // 重写客户端命令为 EVAL rewriteClientCommandArgument(c,0, resetRefCount(createStringObject("EVAL",4))); rewriteClientCommandArgument(c,1,script); } }
static int leaveCritical( lua_State * L ) { lua_sethook( L, luaHook, LUA_MASKLINE, 0 ); return 0; }
static int enterCritical( lua_State * L ) { lua_sethook( L, 0, LUA_MASKLINE, 0 ); return 0; }
bool LuaScriptEngine::init() { // Lua-State initialisation, as well as standard libaries initialisation _state = luaL_newstate(); if (!_state || ! registerStandardLibs() || !registerStandardLibExtensions()) { error("Lua could not be initialized."); return false; } // Register panic callback function lua_atpanic(_state, panicCB); // Error handler for lua_pcall calls // The code below contains a local error handler function const char errorHandlerCode[] = "local function ErrorHandler(message) " " return message .. '\\n' .. debug.traceback('', 2) " "end " "return ErrorHandler"; // Compile the code if (luaL_loadbuffer(_state, errorHandlerCode, strlen(errorHandlerCode), "PCALL ERRORHANDLER") != 0) { // An error occurred, so dislay the reason and exit error("Couldn't compile luaL_pcall errorhandler:\n%s", lua_tostring(_state, -1)); lua_pop(_state, 1); return false; } // Running the code, the error handler function sets the top of the stack if (lua_pcall(_state, 0, 1, 0) != 0) { // An error occurred, so dislay the reason and exit error("Couldn't prepare luaL_pcall errorhandler:\n%s", lua_tostring(_state, -1)); lua_pop(_state, 1); return false; } // Place the error handler function in the Lua registry, and remember the index _pcallErrorhandlerRegistryIndex = luaL_ref(_state, LUA_REGISTRYINDEX); // Initialize the Pluto-Persistence library luaopen_pluto(_state); lua_pop(_state, 1); // Initialize debugging callback if (DebugMan.isDebugChannelEnabled(kDebugScript)) { int mask = 0; if ((gDebugLevel & 1) != 0) mask |= LUA_MASKCALL; if ((gDebugLevel & 2) != 0) mask |= LUA_MASKRET; if ((gDebugLevel & 4) != 0) mask |= LUA_MASKLINE; if (mask != 0) lua_sethook(_state, debugHook, mask, 0); } debugC(kDebugScript, "Lua initialized."); return true; }
lsb_err_value preserve_global_data(lsb_lua_sandbox *lsb) { if (!lsb->lua || !lsb->state_file) { return NULL; } lua_sethook(lsb->lua, NULL, 0, 0); // make sure the string library is loaded before we start lua_getglobal(lsb->lua, LUA_STRLIBNAME); if (!lua_istable(lsb->lua, -1)) { lua_getglobal(lsb->lua, "require"); if (!lua_iscfunction(lsb->lua, -1)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data 'require' function not found"); return LSB_ERR_LUA; } lua_pushstring(lsb->lua, LUA_STRLIBNAME); if (lua_pcall(lsb->lua, 1, 1, 0)) { int len = snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data failed loading 'string'"); if (len >= LSB_ERROR_SIZE || len < 0) { lsb->error_message[LSB_ERROR_SIZE - 1] = 0; } return LSB_ERR_LUA; } } lua_pop(lsb->lua, 1); lua_pushvalue(lsb->lua, LUA_GLOBALSINDEX); FILE *fh = fopen(lsb->state_file, "wb"); if (fh == NULL) { int len = snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data could not open: %s", lsb->state_file); if (len >= LSB_ERROR_SIZE || len < 0) { lsb->error_message[LSB_ERROR_SIZE - 1] = 0; } return LSB_ERR_LUA;; } lsb_err_value ret = NULL; serialization_data data; data.fh = fh; // Clear the sandbox limits during preservation. #ifdef LUA_JIT lua_gc(lsb->lua, LUA_GCSETMEMLIMIT, 0); #else // size_t limit = lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]; lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = 0; #endif // size_t cur_output_size = lsb->output.size; // size_t max_output_size = lsb->output.maxsize; lsb->output.maxsize = 0; // end clear data.tables.size = 64; data.tables.pos = 0; data.tables.array = malloc(data.tables.size * sizeof(table_ref)); if (data.tables.array == NULL || lsb_init_output_buffer(&data.keys, 0)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data out of memory"); ret = LSB_ERR_UTIL_OOM; } else { fprintf(data.fh, "if %s and %s ~= %d then return end\n", preservation_version, preservation_version, get_preservation_version(lsb->lua)); ret = lsb_outputs(&data.keys, "_G", 2); if (!ret) { data.keys.pos += 1; // preserve the NUL in this use case data.globals = lua_topointer(lsb->lua, -1); lua_checkstack(lsb->lua, 2); lua_pushnil(lsb->lua); while (!ret && lua_next(lsb->lua, -2) != 0) { ret = serialize_kvp(lsb, &data, 0); lua_pop(lsb->lua, 1); } } lua_pop(lsb->lua, lua_gettop(lsb->lua)); // Wipe the entire Lua stack. Since incremental cleanup on failure // was added the stack should only contain table _G. } free(data.tables.array); lsb_free_output_buffer(&data.keys); fclose(fh); if (ret) remove(lsb->state_file); // Uncomment if we start preserving state when not destroying the sandbox // Note: serialization uses the output buffer, inprogress output can be // destroyed if the user was collecting output between calls. /* // Restore the sandbox limits after preservation #ifdef LUA_JIT lua_gc(lsb->lua, LUA_GCSETMEMLIMIT, lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]); #else lua_gc(lsb->lua, LUA_GCCOLLECT, 0); lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = limit; lsb->usage[LSB_UT_MEMORY][LSB_US_MAXIMUM] = lsb->usage[LSB_UT_MEMORY][LSB_US_CURRENT]; #endif lsb->output.maxsize = max_output_size; lsb_clear_output_buffer(lsb->output); if (lsb->output.size > cur_output_size) { void* ptr = realloc(lsb->output.data, cur_output_size); if (!ptr) return 1; lsb->output.data = ptr; lsb->output.size = cur_output_size; } // end restore */ return ret; }
void evalGenericCommand(redisClient *c, int evalsha) { lua_State *lua = server.lua; char funcname[43]; long long numkeys; int delhook = 0, err; /* We want the same PRNG sequence at every call so that our PRNG is * not affected by external state. */ redisSrand48(0); /* We set this flag to zero to remember that so far no random command * was called. This way we can allow the user to call commands like * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command * is called (otherwise the replication and AOF would end with non * deterministic sequences). * * Thanks to this flag we'll raise an error every time a write command * is called after a random command was used. */ server.lua_random_dirty = 0; server.lua_write_dirty = 0; /* Get the number of arguments that are keys */ if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != REDIS_OK) return; if (numkeys > (c->argc - 3)) { addReplyError(c,"Number of keys can't be greater than number of args"); return; } /* We obtain the script SHA1, then check if this function is already * defined into the Lua state */ funcname[0] = 'f'; funcname[1] = '_'; if (!evalsha) { /* Hash the code if this is an EVAL call */ sha1hex(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr)); } else { /* We already have the SHA if it is a EVALSHA */ int j; char *sha = c->argv[1]->ptr; /* Convert to lowercase. We don't use tolower since the function * managed to always show up in the profiler output consuming * a non trivial amount of time. */ for (j = 0; j < 40; j++) funcname[j+2] = (sha[j] >= 'A' && sha[j] <= 'Z') ? sha[j]+('a'-'A') : sha[j]; funcname[42] = '\0'; } /* Push the pcall error handler function on the stack. */ lua_getglobal(lua, "__redis__err__handler"); /* Try to lookup the Lua function */ lua_getglobal(lua, funcname); if (lua_isnil(lua,-1)) { lua_pop(lua,1); /* remove the nil from the stack */ /* Function not defined... let's define it if we have the * body of the function. If this is an EVALSHA call we can just * return an error. */ if (evalsha) { lua_pop(lua,1); /* remove the error handler from the stack. */ addReply(c, shared.noscripterr); return; } if (luaCreateFunction(c,lua,funcname,c->argv[1]) == REDIS_ERR) { lua_pop(lua,1); /* remove the error handler from the stack. */ /* The error is sent to the client by luaCreateFunction() * itself when it returns REDIS_ERR. */ return; } /* Now the following is guaranteed to return non nil */ lua_getglobal(lua, funcname); redisAssert(!lua_isnil(lua,-1)); } /* Populate the argv and keys table accordingly to the arguments that * EVAL received. */ luaSetGlobalArray(lua,"KEYS",c->argv+3,(int)numkeys); luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,(int)(c->argc-3-numkeys)); /* Select the right DB in the context of the Lua client */ selectDb(server.lua_client,c->db->id); /* Set a hook in order to be able to stop the script execution if it * is running for too much time. * We set the hook only if the time limit is enabled as the hook will * make the Lua script execution slower. */ server.lua_caller = c; server.lua_time_start = mstime(); server.lua_kill = 0; if (server.lua_time_limit > 0 && server.masterhost == NULL) { lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000); delhook = 1; } /* At this point whether this script was never seen before or if it was * already defined, we can call it. We have zero arguments and expect * a single return value. */ err = lua_pcall(lua,0,1,-2); /* Perform some cleanup that we need to do both on error and success. */ if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */ if (server.lua_timedout) { server.lua_timedout = 0; /* Restore the readable handler that was unregistered when the * script timeout was detected. */ aeCreateFileEvent(server.el,c->fd,AE_READABLE, readQueryFromClient,c); } server.lua_caller = NULL; /* Call the Lua garbage collector from time to time to avoid a * full cycle performed by Lua, which adds too latency. * * The call is performed every LUA_GC_CYCLE_PERIOD executed commands * (and for LUA_GC_CYCLE_PERIOD collection steps) because calling it * for every command uses too much CPU. */ #define LUA_GC_CYCLE_PERIOD 50 { static long gc_count = 0; gc_count++; if (gc_count == LUA_GC_CYCLE_PERIOD) { lua_gc(lua,LUA_GCSTEP,LUA_GC_CYCLE_PERIOD); gc_count = 0; } } if (err) { addReplyErrorFormat(c,"Error running script (call to %s): %s\n", funcname, lua_tostring(lua,-1)); lua_pop(lua,2); /* Consume the Lua reply and remove error handler. */ } else { /* On success convert the Lua return value into Redis protocol, and * send it to * the client. */ luaReplyToRedisReply(c,lua); /* Convert and consume the reply. */ lua_pop(lua,1); /* Remove the error handler. */ } /* EVALSHA should be propagated to Slave and AOF file as full EVAL, unless * we are sure that the script was already in the context of all the * attached slaves *and* the current AOF file if enabled. * * To do so we use a cache of SHA1s of scripts that we already propagated * as full EVAL, that's called the Replication Script Cache. * * For repliation, everytime a new slave attaches to the master, we need to * flush our cache of scripts that can be replicated as EVALSHA, while * for AOF we need to do so every time we rewrite the AOF file. */ if (evalsha) { if (!replicationScriptCacheExists(c->argv[1]->ptr)) { /* This script is not in our script cache, replicate it as * EVAL, then add it into the script cache, as from now on * slaves and AOF know about it. */ robj *script = dictFetchValue(server.lua_scripts,c->argv[1]->ptr); replicationScriptCacheAdd(c->argv[1]->ptr); redisAssertWithInfo(c,NULL,script != NULL); rewriteClientCommandArgument(c,0, resetRefCount(createStringObject("EVAL",4))); rewriteClientCommandArgument(c,1,script); forceCommandPropagation(c,REDIS_PROPAGATE_REPL|REDIS_PROPAGATE_AOF); } } }
void evalGenericCommand(redisClient *c, int evalsha) { lua_State *lua = server.lua; char funcname[43]; long long numkeys; int delhook = 0, err; /* We want the same PRNG sequence at every call so that our PRNG is * not affected by external state. */ redisSrand48(0); /* We set this flag to zero to remember that so far no random command * was called. This way we can allow the user to call commands like * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command * is called (otherwise the replication and AOF would end with non * deterministic sequences). * * Thanks to this flag we'll raise an error every time a write command * is called after a random command was used. */ server.lua_random_dirty = 0; server.lua_write_dirty = 0; /* Get the number of arguments that are keys */ if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != REDIS_OK) return; if (numkeys > (c->argc - 3)) { addReplyError(c,"Number of keys can't be greater than number of args"); return; } /* We obtain the script SHA1, then check if this function is already * defined into the Lua state */ funcname[0] = 'f'; funcname[1] = '_'; if (!evalsha) { /* Hash the code if this is an EVAL call */ sha1hex(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr)); } else { /* We already have the SHA if it is a EVALSHA */ int j; char *sha = c->argv[1]->ptr; for (j = 0; j < 40; j++) funcname[j+2] = tolower(sha[j]); funcname[42] = '\0'; } /* Try to lookup the Lua function */ lua_getglobal(lua, funcname); if (lua_isnil(lua,1)) { lua_pop(lua,1); /* remove the nil from the stack */ /* Function not defined... let's define it if we have the * body of the function. If this is an EVALSHA call we can just * return an error. */ if (evalsha) { addReply(c, shared.noscripterr); return; } if (luaCreateFunction(c,lua,funcname,c->argv[1]) == REDIS_ERR) return; /* Now the following is guaranteed to return non nil */ lua_getglobal(lua, funcname); redisAssert(!lua_isnil(lua,1)); } /* Populate the argv and keys table accordingly to the arguments that * EVAL received. */ luaSetGlobalArray(lua,"KEYS",c->argv+3,numkeys); luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argc-3-numkeys); /* Select the right DB in the context of the Lua client */ selectDb(server.lua_client,c->db->id); /* Set an hook in order to be able to stop the script execution if it * is running for too much time. * We set the hook only if the time limit is enabled as the hook will * make the Lua script execution slower. */ server.lua_caller = c; server.lua_time_start = ustime()/1000; server.lua_kill = 0; if (server.lua_time_limit > 0 && server.masterhost == NULL) { lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000); delhook = 1; } /* At this point whatever this script was never seen before or if it was * already defined, we can call it. We have zero arguments and expect * a single return value. */ err = lua_pcall(lua,0,1,0); /* Perform some cleanup that we need to do both on error and success. */ if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */ if (server.lua_timedout) { server.lua_timedout = 0; /* Restore the readable handler that was unregistered when the * script timeout was detected. */ aeCreateFileEvent(server.el,c->fd,AE_READABLE, readQueryFromClient,c); } server.lua_caller = NULL; selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */ lua_gc(lua,LUA_GCSTEP,1); if (err) { addReplyErrorFormat(c,"Error running script (call to %s): %s\n", funcname, lua_tostring(lua,-1)); lua_pop(lua,1); /* Consume the Lua reply. */ } else { /* On success convert the Lua return value into Redis protocol, and * send it to * the client. */ luaReplyToRedisReply(c,lua); } /* If we have slaves attached we want to replicate this command as * EVAL instead of EVALSHA. We do this also in the AOF as currently there * is no easy way to propagate a command in a different way in the AOF * and in the replication link. * * IMPROVEMENT POSSIBLE: * 1) Replicate this command as EVALSHA in the AOF. * 2) Remember what slave already received a given script, and replicate * the EVALSHA against this slaves when possible. */ if (evalsha) { robj *script = dictFetchValue(server.lua_scripts,c->argv[1]->ptr); redisAssertWithInfo(c,NULL,script != NULL); rewriteClientCommandArgument(c,0, resetRefCount(createStringObject("EVAL",4))); rewriteClientCommandArgument(c,1,script); } }
static void lstop(lua_State *L, GT_UNUSED lua_Debug *ar) { lua_sethook(L, NULL, 0, 0); luaL_error(L, "interrupted!"); }
lsb_err_value lsb_init(lsb_lua_sandbox *lsb, const char *state_file) { if (!lsb) { return LSB_ERR_UTIL_NULL; } if (lsb->state != LSB_UNKNOWN) { lsb_terminate(lsb, LSB_ERR_INIT); return LSB_ERR_INIT; } if (state_file && strlen(state_file) > 0) { lsb->state_file = malloc(strlen(state_file) + 1); if (!lsb->state_file) { lsb_terminate(lsb, LSB_ERR_UTIL_OOM); return LSB_ERR_UTIL_OOM; } strcpy(lsb->state_file, state_file); } #ifndef LUA_JIT size_t mem_limit = lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]; lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = 0; #endif preload_modules(lsb->lua); // load package module lua_pushcfunction(lsb->lua, luaopen_package); lua_pushstring(lsb->lua, LUA_LOADLIBNAME); lua_call(lsb->lua, 1, 1); lua_newtable(lsb->lua); lua_setmetatable(lsb->lua, -2); lua_pop(lsb->lua, 1); // load base module lua_getglobal(lsb->lua, "require"); if (!lua_iscfunction(lsb->lua, -1)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "lsb_init() 'require' not found"); lsb_terminate(lsb, NULL); return LSB_ERR_LUA; } lua_pushstring(lsb->lua, LUA_BASELIBNAME); if (lua_pcall(lsb->lua, 1, 0, 0)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "lsb_init %s", lua_tostring(lsb->lua, -1)); lsb_terminate(lsb, NULL); return LSB_ERR_LUA; } if (lsb->usage[LSB_UT_INSTRUCTION][LSB_US_LIMIT] != 0) { lua_sethook(lsb->lua, instruction_manager, LUA_MASKCOUNT, (int)lsb->usage[LSB_UT_INSTRUCTION][LSB_US_LIMIT]); } else { lua_sethook(lsb->lua, NULL, 0, 0); } #ifdef LUA_JIT // todo limit lua_gc(lsb->lua, LUA_GCSETMEMLIMIT, (int)lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]); #else lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = mem_limit; #endif lua_CFunction pf = lua_atpanic(lsb->lua, unprotected_panic); int jump = setjmp(g_jbuf); if (jump || luaL_dofile(lsb->lua, lsb->lua_file) != 0) { int len = snprintf(lsb->error_message, LSB_ERROR_SIZE, "%s", lua_tostring(lsb->lua, -1)); if (len >= LSB_ERROR_SIZE || len < 0) { lsb->error_message[LSB_ERROR_SIZE - 1] = 0; } lsb_terminate(lsb, NULL); return LSB_ERR_LUA; } else { lua_gc(lsb->lua, LUA_GCCOLLECT, 0); lsb->usage[LSB_UT_INSTRUCTION][LSB_US_CURRENT] = instruction_usage(lsb); if (lsb->usage[LSB_UT_INSTRUCTION][LSB_US_CURRENT] > lsb->usage[LSB_UT_INSTRUCTION][LSB_US_MAXIMUM]) { lsb->usage[LSB_UT_INSTRUCTION][LSB_US_MAXIMUM] = lsb->usage[LSB_UT_INSTRUCTION][LSB_US_CURRENT]; } lsb->state = LSB_RUNNING; if (lsb->state_file) { lsb_err_value ret = restore_global_data(lsb); if (ret) return ret; } } lua_atpanic(lsb->lua, pf); return NULL; }
static int profiler_stop( lua_State * L) { lua_sethook(L,NULL,0,0); return 0; }
void clua_setexecutionlimit(lua_State* L, int n) { lua_sethook(L, &clua_hook_function, LUA_MASKCOUNT, n); }
static int profiler_stop(lua_State *L) { CALL *call; int incl_duration, count, linedefined, line; const char *caller_source = NULL; const char *caller_name = NULL; const char *source = NULL; const char *name = NULL; /* Deregister the callhook */ lua_sethook(L, (lua_Hook)callhook, 0, 0); /* Deallocate the call_stack */ free(call_stack); /* Output the calls */ qsort(calls, num_calls, sizeof(CALL), cmpcalls); fprintf(f, "events: Time\n\n"); for (int i = 0; i < num_calls; i ++) { call = &calls[i]; if (caller_source == NULL || caller_name == NULL || source == NULL || name == NULL) { caller_source = call->caller_source; caller_name = call->caller_name; source = call->source; name = call->name; linedefined = call->linedefined; line = call->line; incl_duration = 0; count = 0; fprintf(f, "\nfl=%s\nfn=%s\n", caller_source, caller_name); } else if (strcmp(caller_source, call->caller_source) != 0 || strcmp(caller_name, call->caller_name) != 0) { fprintf(f, "cfi=%s\ncfn=%s\ncalls=%d %d\n%d %d\n", source, name, count, linedefined, line, incl_duration); caller_source = call->caller_source; caller_name = call->caller_name; source = call->source; name = call->name; linedefined = call->linedefined; line = call->line; incl_duration = 0; count = 0; fprintf(f, "\nfl=%s\nfn=%s\n", caller_source, caller_name); } else if (strcmp(source, call->source) != 0 || strcmp(name, call->name) != 0) { fprintf(f, "cfi=%s\ncfn=%s\ncalls=%d %d\n%d %d\n", source, name, count, linedefined, line, incl_duration); source = call->source; name = call->name; linedefined = call->linedefined; line = call->line; incl_duration = 0; count = 0; } fprintf(f, "%d %d\n", call->line, call->excl_duration); if (call->incl_end_time != 0) { incl_duration += (int)(call->incl_end_time - call->incl_start_time); } count += 1; } if (source != NULL && name != NULL) { fprintf(f, "cfi=%s\ncfn=%s\ncalls=%d %d\n%d %d\n", source, name, count, linedefined, line, incl_duration); } free(calls); fclose(f); /* Return success */ lua_pushboolean(L, 1); return 1; }
bool LuaHostWindows::AttachLuaHook( lua_State* lvm, lua_Hook hook, int mask, int count ) { lua_sethook(lvm, hook, mask, count); return true; }
void evalGenericCommand(rliteClient *c, int evalsha) { scriptingInit(); lua_client->context = c->context; char funcname[43]; long long numkeys; int delhook = 0, err; /* We want the same PRNG sequence at every call so that our PRNG is * not affected by external state. */ rliteSrand48(0); /* We set this flag to zero to remember that so far no random command * was called. This way we can allow the user to call commands like * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command * is called (otherwise the replication and AOF would end with non * deterministic sequences). * * Thanks to this flag we'll raise an error every time a write command * is called after a random command was used. */ lua_random_dirty = 0; lua_write_dirty = 0; /* Get the number of arguments that are keys */ if (getLongLongFromObjectOrReply(c,c->argv[2],c->argvlen[2],&numkeys,NULL) != RLITE_OK) return; if (numkeys > (c->argc - 3)) { c->reply = createErrorObject("Number of keys can't be greater than number of args"); return; } else if (numkeys < 0) { c->reply = createErrorObject("Number of keys can't be negative"); return; } /* We obtain the script SHA1, then check if this function is already * defined into the Lua state */ funcname[0] = 'f'; funcname[1] = '_'; if (!evalsha) { /* Hash the code if this is an EVAL call */ sha1hex(funcname+2,c->argv[1],c->argvlen[1]); } else { /* We already have the SHA if it is a EVALSHA */ int j; char *sha = c->argv[1]; /* Convert to lowercase. We don't use tolower since the function * managed to always show up in the profiler output consuming * a non trivial amount of time. */ for (j = 0; j < 40; j++) funcname[j+2] = (sha[j] >= 'A' && sha[j] <= 'Z') ? sha[j]+('a'-'A') : sha[j]; funcname[42] = '\0'; char *body; long bodylen; int retval = getScript(c, funcname + 2, &body, &bodylen); if (retval != RL_OK) { c->reply = createErrorObject(RLITE_NOSCRIPTERR); return; } luaCreateFunction(c, lua, funcname, body, bodylen); rl_free(body); } /* Push the pcall error handler function on the stack. */ lua_getglobal(lua, "__rlite__err__handler"); /* Try to lookup the Lua function */ lua_getglobal(lua, funcname); if (lua_isnil(lua,-1)) { lua_pop(lua,1); /* remove the nil from the stack */ /* Function not defined... let's define it if we have the * body of the function. If this is an EVALSHA call we can just * return an error. */ if (evalsha) { lua_pop(lua,1); /* remove the error handler from the stack. */ c->reply = createErrorObject(RLITE_NOSCRIPTERR); return; } if (luaCreateFunction(c,lua,funcname,c->argv[1], c->argvlen[1]) == RLITE_ERR) { lua_pop(lua,1); /* remove the error handler from the stack. */ /* The error is sent to the client by luaCreateFunction() * itself when it returns RLITE_ERR. */ return; } /* Now the following is guaranteed to return non nil */ lua_getglobal(lua, funcname); if (lua_isnil(lua,-1)) { // TODO: panic return; } } /* Populate the argv and keys table accordingly to the arguments that * EVAL received. */ luaSetGlobalArray(lua,"KEYS",c->argv+3,c->argvlen+3,numkeys); luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argvlen+3+numkeys,c->argc-3-numkeys); /* Set a hook in order to be able to stop the script execution if it * is running for too much time. * We set the hook only if the time limit is enabled as the hook will * make the Lua script execution slower. */ lua_caller = c; lua_time_start = rl_mstime(); lua_kill = 0; if (lua_time_limit > 0) { lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000); delhook = 1; } /* At this point whether this script was never seen before or if it was * already defined, we can call it. We have zero arguments and expect * a single return value. */ err = lua_pcall(lua,0,1,-2); /* Perform some cleanup that we need to do both on error and success. */ if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */ if (lua_timedout) { lua_timedout = 0; /* Restore the readable handler that was unregistered when the * script timeout was detected. */ } lua_caller = NULL; /* Call the Lua garbage collector from time to time to avoid a * full cycle performed by Lua, which adds too latency. * * The call is performed every LUA_GC_CYCLE_PERIOD executed commands * (and for LUA_GC_CYCLE_PERIOD collection steps) because calling it * for every command uses too much CPU. */ #define LUA_GC_CYCLE_PERIOD 50 { static long gc_count = 0; gc_count++; if (gc_count == LUA_GC_CYCLE_PERIOD) { lua_gc(lua,LUA_GCSTEP,LUA_GC_CYCLE_PERIOD); gc_count = 0; } } if (err) { char err[1024]; snprintf(err, 1024, "Error running script (call to %s): %s\n", funcname, lua_tostring(lua,-1)); c->reply = createErrorObject(err); lua_pop(lua,2); /* Consume the Lua reply and remove error handler. */ } else { /* On success convert the Lua return value into Redis protocol, and * send it to * the client. */ luaReplyToRedisReply(c,lua); /* Convert and consume the reply. */ lua_pop(lua,1); /* Remove the error handler. */ } }
void interpreter_interrupt_probe (void) { interrupted = false; lua_sethook(L, NULL, 0, 0); luaL_error(L, "interrupted!"); }
/* *** */ int register_lua_globals(struct lua_State *lua, const char* script_directory, const char* filename) { int i, error = 0, idx = 1; /* add standard libs */ luaL_openlibs(lua); /* add specific functions */ lua_register(lua, L_FUNCTION_PREFIX"add_job", lf_add_job); lua_register(lua, L_FUNCTION_PREFIX"add_output", lf_add_output); lua_register(lua, L_FUNCTION_PREFIX"add_clean", lf_add_clean); lua_register(lua, L_FUNCTION_PREFIX"add_pseudo", lf_add_pseudo); lua_register(lua, L_FUNCTION_PREFIX"add_dependency", lf_add_dependency); lua_register(lua, L_FUNCTION_PREFIX"add_constraint_shared", lf_add_constraint_shared); lua_register(lua, L_FUNCTION_PREFIX"add_constraint_exclusive", lf_add_constraint_exclusive); lua_register(lua, L_FUNCTION_PREFIX"default_target", lf_default_target); lua_register(lua, L_FUNCTION_PREFIX"set_filter", lf_set_filter); lua_register(lua, L_FUNCTION_PREFIX"set_priority", lf_set_priority); lua_register(lua, L_FUNCTION_PREFIX"modify_priority", lf_modify_priority); /* advanced dependency checkers */ lua_register(lua, L_FUNCTION_PREFIX"add_dependency_cpp_set_paths", lf_add_dependency_cpp_set_paths); lua_register(lua, L_FUNCTION_PREFIX"add_dependency_cpp", lf_add_dependency_cpp); lua_register(lua, L_FUNCTION_PREFIX"add_dependency_search", lf_add_dependency_search); /* path manipulation */ lua_register(lua, L_FUNCTION_PREFIX"path_join", lf_path_join); lua_register(lua, L_FUNCTION_PREFIX"path_normalize", lf_path_normalize); lua_register(lua, L_FUNCTION_PREFIX"path_isnice", lf_path_isnice); lua_register(lua, L_FUNCTION_PREFIX"path_ext", lf_path_ext); lua_register(lua, L_FUNCTION_PREFIX"path_dir", lf_path_dir); lua_register(lua, L_FUNCTION_PREFIX"path_base", lf_path_base); lua_register(lua, L_FUNCTION_PREFIX"path_filename", lf_path_filename); /* various support functions */ lua_register(lua, L_FUNCTION_PREFIX"collect", lf_collect); lua_register(lua, L_FUNCTION_PREFIX"collectrecursive", lf_collectrecursive); lua_register(lua, L_FUNCTION_PREFIX"collectdirs", lf_collectdirs); lua_register(lua, L_FUNCTION_PREFIX"collectdirsrecursive", lf_collectdirsrecursive); lua_register(lua, L_FUNCTION_PREFIX"listdir", lf_listdir); lua_register(lua, L_FUNCTION_PREFIX"update_globalstamp", lf_update_globalstamp); lua_register(lua, L_FUNCTION_PREFIX"loadfile", lf_loadfile); lua_register(lua, L_FUNCTION_PREFIX"mkdir", lf_mkdir); lua_register(lua, L_FUNCTION_PREFIX"mkdirs", lf_mkdirs); lua_register(lua, L_FUNCTION_PREFIX"fileexist", lf_fileexist); lua_register(lua, L_FUNCTION_PREFIX"nodeexist", lf_nodeexist); lua_register(lua, L_FUNCTION_PREFIX"hash", lf_hash); lua_register(lua, L_FUNCTION_PREFIX"isstring", lf_isstring); lua_register(lua, L_FUNCTION_PREFIX"istable", lf_istable); lua_register(lua, L_FUNCTION_PREFIX"isoutput", lf_isoutput); lua_register(lua, L_FUNCTION_PREFIX"table_walk", lf_table_walk); lua_register(lua, L_FUNCTION_PREFIX"table_deepcopy", lf_table_deepcopy); lua_register(lua, L_FUNCTION_PREFIX"table_tostring", lf_table_tostring); lua_register(lua, L_FUNCTION_PREFIX"table_flatten", lf_table_flatten); /* error handling */ lua_register(lua, "errorfunc", lf_errorfunc); /* create arguments table */ lua_pushstring(lua, CONTEXT_LUA_SCRIPTARGS_TABLE); lua_newtable(lua); for(i = 0; i < option_num_scriptargs; i++) { const char *separator = option_scriptargs[i]; while(*separator != '=' && *separator != '\0') separator++; if(*separator == '\0') { lua_pushnumber(lua, idx++); lua_pushstring(lua, option_scriptargs[i]); } else { lua_pushlstring(lua, option_scriptargs[i], separator-option_scriptargs[i]); lua_pushstring(lua, separator+1); } lua_settable(lua, -3); } lua_settable(lua, LUA_GLOBALSINDEX); /* create targets table */ lua_pushstring(lua, CONTEXT_LUA_TARGETS_TABLE); lua_newtable(lua); for(i = 0; i < option_num_targets; i++) { lua_pushstring(lua, option_targets[i]); lua_rawseti(lua, -2, i); } lua_settable(lua, LUA_GLOBALSINDEX); /* set paths */ { char cwd[MAX_PATH_LENGTH]; if(!getcwd(cwd, sizeof(cwd))) { printf("%s: error: couldn't get current working directory\n", session.name); return -1; } lua_setglobalstring(lua, CONTEXT_LUA_PATH, script_directory); lua_setglobalstring(lua, CONTEXT_LUA_WORKPATH, cwd); } /* set version, family, platform, arch, verbocity */ lua_setglobalstring(lua, "_bam_version", BAM_VERSION_STRING); lua_setglobalstring(lua, "_bam_version_complete", BAM_VERSION_STRING_COMPLETE); lua_setglobalstring(lua, "family", BAM_FAMILY_STRING); lua_setglobalstring(lua, "platform", BAM_PLATFORM_STRING); lua_setglobalstring(lua, "arch", BAM_ARCH_STRING); lua_setglobalstring(lua, "_bam_exe", session.exe); lua_setglobalstring(lua, "_bam_modulefilename", filename); lua_pushnumber(lua, session.verbose); lua_setglobal(lua, "verbose"); if(option_debug_trace_vm) lua_sethook(lua, lua_vm_trace_hook, LUA_MASKCOUNT, 1); /* load base script */ if(!option_debug_nointernal) { int ret; const char *p; int f; for(f = 0; internal_files[f].filename; f++) { p = internal_files[f].content; if(session.verbose) printf("%s: reading internal file '%s'\n", session.name, internal_files[f].filename); lua_getglobal(lua, "errorfunc"); /* push error function to stack */ ret = lua_load(lua, internal_base_reader, (void *)&p, internal_files[f].filename); if(ret != 0) { lf_errorfunc(lua); if(ret == LUA_ERRSYNTAX) { } else if(ret == LUA_ERRMEM) printf("%s: memory allocation error\n", session.name); else printf("%s: unknown error parsing base script\n", session.name); error = 1; } else if(lua_pcall(lua, 0, LUA_MULTRET, -2) != 0) error = 1; } } return error; }
/***************************************************************************** Clear function execution guard *****************************************************************************/ static void luascript_hook_end(lua_State *L) { #if LUASCRIPT_CHECKINTERVAL lua_sethook(L, luascript_exec_check, 0, 0); #endif }
static void nlua_thread(int pin, int pout, char *project, char *filename) { char cmd[4096]; int cmd_size; fprintf(stderr, "[err] Starting up Lua interpreter...\n"); fprintf(stdout, "[out] Starting up Lua interpreter...\n"); lua_State *L; L = lua_open(); if (!L) { cmd[0] = LC_ERROR; cmd_size = snprintf(cmd+1, sizeof(cmd)-2, "Unable to open lua") + 1; write(1, cmd, cmd_size); exit(0); } luaL_openlibs(L); lua_sethook(L, nlua_interpret_hook, LUA_MASKLINE, 0); /* If a filename was specified, load it in and run it */ if (project && *project) { char full_filename[2048]; if (filename && *filename) snprintf(full_filename, sizeof(full_filename)-1, "%s/%s/%s", PROJECT_DIR, project, filename); else snprintf(full_filename, sizeof(full_filename)-1, "%s/%s", PROJECT_DIR, project); if (luaL_dofile(L, full_filename)) { cmd[0] = LC_ERROR; cmd_size = snprintf(cmd+1, sizeof(cmd)-2, "Error: %s", lua_tostring(L, 1)) + 1; write(1, cmd, cmd_size); } } /* If no file was specified, enter REPL mode */ else { printf("Entering REPL mode...\n"); int status; while ((status = loadline(L)) != -1) { if (status == 0) status = docall(L, 0, 0); report(L, status); if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) l_message(progname, lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); } } lua_settop(L, 0); fputs("\n", stdout); fflush(stdout); } lua_close(L); close(pin); close(pout); exit(0); return; }
static void laction (int i) { signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); }
int lua_sandbox_init(lua_sandbox* lsb, const char* data_file) { if (lsb == NULL || lsb->m_lua != NULL) { return 0; } if (lsb->m_lua_file == NULL) { snprintf(lsb->m_error_message, ERROR_SIZE, "no Lua script provided"); sandbox_terminate(lsb); return 1; } lsb->m_lua = lua_newstate(memory_manager, lsb); if (lsb->m_lua == NULL) { snprintf(lsb->m_error_message, ERROR_SIZE, "out of memory"); sandbox_terminate(lsb); return 2; } load_library(lsb->m_lua, "", luaopen_base, disable_base_functions); lua_pop(lsb->m_lua, 1); load_library(lsb->m_lua, LUA_MATHLIBNAME, luaopen_math, disable_none); lua_pop(lsb->m_lua, 1); load_library(lsb->m_lua, LUA_OSLIBNAME, luaopen_os, disable_os_functions); lua_pop(lsb->m_lua, 1); load_library(lsb->m_lua, LUA_STRLIBNAME, luaopen_string, disable_none); lua_pop(lsb->m_lua, 1); load_library(lsb->m_lua, LUA_TABLIBNAME, luaopen_table, disable_none); lua_pop(lsb->m_lua, 1); load_library(lsb->m_lua, heka_circular_buffer_table, luaopen_circular_buffer, disable_none); lua_pop(lsb->m_lua, 1); lua_pushcfunction(lsb->m_lua, &require_library); lua_setglobal(lsb->m_lua, "require"); lua_pushlightuserdata(lsb->m_lua, (void*)lsb); lua_pushcclosure(lsb->m_lua, &read_config, 1); lua_setglobal(lsb->m_lua, "read_config"); lua_pushlightuserdata(lsb->m_lua, (void*)lsb); lua_pushcclosure(lsb->m_lua, &read_message, 1); lua_setglobal(lsb->m_lua, "read_message"); lua_pushlightuserdata(lsb->m_lua, (void*)lsb); lua_pushcclosure(lsb->m_lua, &output, 1); lua_setglobal(lsb->m_lua, "output"); lua_pushlightuserdata(lsb->m_lua, (void*)lsb); lua_pushcclosure(lsb->m_lua, &inject_message, 1); lua_setglobal(lsb->m_lua, "inject_message"); lua_sethook(lsb->m_lua, instruction_manager, LUA_MASKCOUNT, lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_LIMIT]); if (luaL_dofile(lsb->m_lua, lsb->m_lua_file) != 0) { snprintf(lsb->m_error_message, ERROR_SIZE, "%s", lua_tostring(lsb->m_lua, -1)); sandbox_terminate(lsb); return 3; } else { lua_gc(lsb->m_lua, LUA_GCCOLLECT, 0); lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] = instruction_usage(lsb); if (lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM]) { lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM] = lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT]; } lsb->m_status = STATUS_RUNNING; if (data_file != NULL && strlen(data_file) > 0) { return restore_global_data(lsb, data_file); } } return 0; }