summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2017-07-23 12:55:37 +0200
committerantirez <antirez@gmail.com>2017-07-23 12:55:37 +0200
commit314043552b3e0ce5f080d0fd2169d5c32f94a222 (patch)
tree7f9f6b9eacee79926364a92a1d75ecd71c42e47b
parent5bfdfbe1742f113d3ea1d0dbe857b805da4e3381 (diff)
downloadredis-314043552b3e0ce5f080d0fd2169d5c32f94a222.tar.gz
Modules: don't crash when Lua calls a module blocking command.
Lua scripting does not support calling blocking commands, however all the native Redis commands are flagged as "s" (no scripting flag), so this is not possible at all. With modules there is no such mechanism in order to flag a command as non callable by the Lua scripting engine, moreover we cannot trust the modules users from complying all the times: it is likely that modules will be released to have blocking commands without such commands being flagged correctly, even if we provide a way to signal this fact. This commit attempts to address the problem in a short term way, by detecting that a module is trying to block in the context of the Lua scripting engine client, and preventing to do this. The module will actually believe to block as usually, but what happens is that the Lua script receives an error immediately, and the background call is ignored by the Redis engine (if not for the cleanup callbacks, once it unblocks). Long term, the more likely solution, is to introduce a new call called RedisModule_GetClientFlags(), so that a command can detect if the caller is a Lua script, and return an error, or avoid blocking at all. Being the blocking API experimental right now, more work is needed in this regard in order to reach a level well blocking module commands and all the other Redis subsystems interact peacefully. Now the effect is like the following: 127.0.0.1:6379> eval "redis.call('hello.block',1,5000)" 0 (error) ERR Error running script (call to f_b5ba35ff97bc1ef23debc4d6e9fd802da187ed53): @user_script:1: ERR Blocking module command called from Lua script This commit fixes issue #4127 in the short term.
-rw-r--r--src/module.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/src/module.c b/src/module.c
index de1a740ec..fda68b273 100644
--- a/src/module.c
+++ b/src/module.c
@@ -3332,10 +3332,15 @@ void unblockClientFromModule(client *c) {
*/
RedisModuleBlockedClient *RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms) {
client *c = ctx->client;
+ int islua = c->flags & CLIENT_LUA;
+
c->bpop.module_blocked_handle = zmalloc(sizeof(RedisModuleBlockedClient));
RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle;
- bc->client = c;
+ /* We need to handle the invalid operation of calling modules blocking
+ * commands from Lua. We actually create an already aborted (client set to
+ * NULL) blocked client handle, and actually reply to Lua with an error. */
+ bc->client = islua ? NULL : c;
bc->module = ctx->module;
bc->reply_callback = reply_callback;
bc->timeout_callback = timeout_callback;
@@ -3346,7 +3351,12 @@ RedisModuleBlockedClient *RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc
bc->dbid = c->db->id;
c->bpop.timeout = timeout_ms ? (mstime()+timeout_ms) : 0;
- blockClient(c,BLOCKED_MODULE);
+ if (islua) {
+ c->bpop.module_blocked_handle = NULL;
+ addReplyError(c,"Blocking module command called from Lua script");
+ } else {
+ blockClient(c,BLOCKED_MODULE);
+ }
return bc;
}