X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/e108bab0437c709fcc8f339677bf6295fa793163..882b65ceafc3003e20c5a48bf1a253e09084f44f:/src/scripting.c diff --git a/src/scripting.c b/src/scripting.c index e952c7c6..f62e5c29 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -158,24 +158,37 @@ int luaRedisCommand(lua_State *lua) { return 1; } + /* Setup our fake client for command execution */ + c->argv = argv; + c->argc = argc; + /* Command lookup */ cmd = lookupCommand(argv[0]->ptr); if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) || (argc < -cmd->arity))) { - for (j = 0; j < argc; j++) decrRefCount(argv[j]); - zfree(argv); if (cmd) luaPushError(lua, "Wrong number of args calling Redis command From Lua script"); else luaPushError(lua,"Unknown Redis command called from Lua script"); - return 1; + goto cleanup; } - /* Run the command in the context of a fake client */ - c->argv = argv; - c->argc = argc; + if (cmd->flags & REDIS_CMD_NOSCRIPT) { + luaPushError(lua, "This Redis command is not allowed from scripts"); + goto cleanup; + } + + if (cmd->flags & REDIS_CMD_WRITE && server.lua_random_dirty) { + luaPushError(lua, + "Write commands not allowed after non deterministic commands"); + goto cleanup; + } + + if (cmd->flags & REDIS_CMD_RANDOM) server.lua_random_dirty = 1; + + /* Run the command */ cmd->proc(c); /* Convert the result of the Redis command into a suitable Lua type. @@ -195,6 +208,7 @@ int luaRedisCommand(lua_State *lua) { redisProtocolToLuaType(lua,reply); sdsfree(reply); +cleanup: /* Clean up. Command code may have changed argv/argc so we use the * argv/argc of the client instead of the local variables. */ for (j = 0; j < c->argc; j++) @@ -419,6 +433,16 @@ void evalGenericCommand(redisClient *c, int evalsha) { * 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; + /* Get the number of arguments that are keys */ if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != REDIS_OK) return;