Ejemplo n.º 1
0
static void lstop (lua_State *L, lua_Debug *ar) {
  (void)ar;  /* unused arg. */
  lua_sethook(L, NULL, 0, 0);
  luaL_error(L, "interrupted!");
}
Ejemplo n.º 2
0
static void laction(int i)
{
	signal(i, SIG_DFL);
	lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}
Ejemplo n.º 3
0
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;

}
Ejemplo n.º 5
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);
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
static void laction(int i)
{
	signal(i, G.PluginData.old_action);
	lua_sethook(G.LS, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}
Ejemplo n.º 8
0
static void sig_postpone (int i) {
	signalno = i;
	lua_sethook(signalL, sig_handle, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}
Ejemplo n.º 9
0
int aura_setup_vm_protection(lua_State *L, int cnt)
{
	count = cnt;
	lua_sethook (L, handle_runaway, LUA_MASKCOUNT, count);
	return 0;
}
Ejemplo n.º 10
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);
    }
}
Ejemplo n.º 11
0
static int leaveCritical( lua_State * L )
{
    lua_sethook( L, luaHook, LUA_MASKLINE, 0 );
    return 0;
}
Ejemplo n.º 12
0
static int enterCritical( lua_State * L )
{
    lua_sethook( L, 0, LUA_MASKLINE, 0 );
    return 0;
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
0
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;
}
Ejemplo n.º 15
0
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);
        }
    }
}
Ejemplo n.º 16
0
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);
    }
}
Ejemplo n.º 17
0
static void lstop(lua_State *L, GT_UNUSED lua_Debug *ar) {
  lua_sethook(L, NULL, 0, 0);
  luaL_error(L, "interrupted!");
}
Ejemplo n.º 18
0
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;
}
Ejemplo n.º 19
0
static int profiler_stop( lua_State * L)
{
	lua_sethook(L,NULL,0,0);
	return 0;
}
Ejemplo n.º 20
0
void clua_setexecutionlimit(lua_State* L, int n) {
  lua_sethook(L, &clua_hook_function, LUA_MASKCOUNT, n);
}
Ejemplo n.º 21
0
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;
}
Ejemplo n.º 22
0
bool LuaHostWindows::AttachLuaHook( lua_State* lvm, lua_Hook hook, int mask, int count )
{
	lua_sethook(lvm, hook, mask, count);
	return true;
}
Ejemplo n.º 23
0
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. */
	}
}
Ejemplo n.º 24
0
void interpreter_interrupt_probe (void)
{
    interrupted = false;
    lua_sethook(L, NULL, 0, 0);
    luaL_error(L, "interrupted!");
}
Ejemplo n.º 25
0
Archivo: main.c Proyecto: malind/bam
/* *** */
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;
}
Ejemplo n.º 26
0
/*****************************************************************************
  Clear function execution guard
*****************************************************************************/
static void luascript_hook_end(lua_State *L)
{
#if LUASCRIPT_CHECKINTERVAL
  lua_sethook(L, luascript_exec_check, 0, 0);
#endif
}
Ejemplo n.º 27
0
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;
}
Ejemplo n.º 28
0
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);
}
Ejemplo n.º 29
0
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;
}