summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/module.c17
-rw-r--r--src/server.c31
-rw-r--r--src/server.h1
-rw-r--r--tests/unit/moduleapi/misc.tcl23
4 files changed, 52 insertions, 20 deletions
diff --git a/src/module.c b/src/module.c
index f0f49837b..776d74b65 100644
--- a/src/module.c
+++ b/src/module.c
@@ -592,6 +592,7 @@ void moduleReleaseTempClient(client *c) {
c->bufpos = 0;
c->flags = CLIENT_MODULE;
c->user = NULL; /* Root user */
+ c->cmd = c->lastcmd = c->realcmd = NULL;
moduleTempClients[moduleTempClientCount++] = c;
}
@@ -5781,7 +5782,6 @@ fmterr:
* This API is documented here: https://redis.io/topics/modules-intro
*/
RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) {
- struct redisCommand *cmd;
client *c = NULL;
robj **argv = NULL;
int argc = 0, argv_len = 0, flags = 0;
@@ -5789,6 +5789,7 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
RedisModuleCallReply *reply = NULL;
int replicate = 0; /* Replicate this command? */
int error_as_call_replies = 0; /* return errors as RedisModuleCallReply object */
+ uint64_t cmd_flags;
/* Handle arguments. */
va_start(ap, fmt);
@@ -5831,7 +5832,7 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
/* Lookup command now, after filters had a chance to make modifications
* if necessary.
*/
- cmd = c->cmd = c->lastcmd = c->realcmd = lookupCommand(c->argv,c->argc);
+ c->cmd = c->lastcmd = c->realcmd = lookupCommand(c->argv,c->argc);
sds err;
if (!commandCheckExistence(c, error_as_call_replies? &err : NULL)) {
errno = ENOENT;
@@ -5846,10 +5847,12 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
goto cleanup;
}
+ cmd_flags = getCommandFlags(c);
+
if (flags & REDISMODULE_ARGV_SCRIPT_MODE) {
/* Basically on script mode we want to only allow commands that can
* be executed on scripts (CMD_NOSCRIPT is not set on the command flags) */
- if (cmd->flags & CMD_NOSCRIPT) {
+ if (cmd_flags & CMD_NOSCRIPT) {
errno = ESPIPE;
if (error_as_call_replies) {
sds msg = sdscatfmt(sdsempty(), "command '%S' is not allowed on script mode", c->cmd->fullname);
@@ -5860,7 +5863,7 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
}
if (flags & REDISMODULE_ARGV_RESPECT_DENY_OOM) {
- if (cmd->flags & CMD_DENYOOM) {
+ if (cmd_flags & CMD_DENYOOM) {
int oom_state;
if (ctx->flags & REDISMODULE_CTX_THREAD_SAFE) {
/* On background thread we can not count on server.pre_command_oom_state.
@@ -5882,7 +5885,7 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
}
if (flags & REDISMODULE_ARGV_NO_WRITES) {
- if (cmd->flags & CMD_WRITE) {
+ if (cmd_flags & CMD_WRITE) {
errno = ENOSPC;
if (error_as_call_replies) {
sds msg = sdscatfmt(sdsempty(), "Write command '%S' was "
@@ -5895,7 +5898,7 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
/* Script mode tests */
if (flags & REDISMODULE_ARGV_SCRIPT_MODE) {
- if (cmd->flags & CMD_WRITE) {
+ if (cmd_flags & CMD_WRITE) {
/* on script mode, if a command is a write command,
* We will not run it if we encounter disk error
* or we do not have enough replicas */
@@ -5932,7 +5935,7 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
}
if (server.masterhost && server.repl_state != REPL_STATE_CONNECTED &&
- server.repl_serve_stale_data == 0 && !(cmd->flags & CMD_STALE)) {
+ server.repl_serve_stale_data == 0 && !(cmd_flags & CMD_STALE)) {
errno = ESPIPE;
if (error_as_call_replies) {
sds msg = sdsdup(shared.masterdownerr->ptr);
diff --git a/src/server.c b/src/server.c
index 6b1d1194f..797c79fc3 100644
--- a/src/server.c
+++ b/src/server.c
@@ -3604,6 +3604,23 @@ int commandCheckArity(client *c, sds *err) {
return 1;
}
+/* If we're executing a script, try to extract a set of command flags from
+ * it, in case it declared them. Note this is just an attempt, we don't yet
+ * know the script command is well formed.*/
+uint64_t getCommandFlags(client *c) {
+ uint64_t cmd_flags = c->cmd->flags;
+
+ if (c->cmd->proc == fcallCommand || c->cmd->proc == fcallroCommand) {
+ cmd_flags = fcallGetCommandFlags(c, cmd_flags);
+ } else if (c->cmd->proc == evalCommand || c->cmd->proc == evalRoCommand ||
+ c->cmd->proc == evalShaCommand || c->cmd->proc == evalShaRoCommand)
+ {
+ cmd_flags = evalGetCommandFlags(c, cmd_flags);
+ }
+
+ return cmd_flags;
+}
+
/* If this function gets called we already read a whole
* command, arguments are in the client argv/argc fields.
* processCommand() execute the command or prepare the
@@ -3668,19 +3685,7 @@ int processCommand(client *c) {
}
}
- /* If we're executing a script, try to extract a set of command flags from
- * it, in case it declared them. Note this is just an attempt, we don't yet
- * know the script command is well formed.*/
- uint64_t cmd_flags = c->cmd->flags;
- if (c->cmd->proc == evalCommand || c->cmd->proc == evalShaCommand ||
- c->cmd->proc == evalRoCommand || c->cmd->proc == evalShaRoCommand ||
- c->cmd->proc == fcallCommand || c->cmd->proc == fcallroCommand)
- {
- if (c->cmd->proc == fcallCommand || c->cmd->proc == fcallroCommand)
- cmd_flags = fcallGetCommandFlags(c, cmd_flags);
- else
- cmd_flags = evalGetCommandFlags(c, cmd_flags);
- }
+ uint64_t cmd_flags = getCommandFlags(c);
int is_read_command = (cmd_flags & CMD_READONLY) ||
(c->cmd->proc == execCommand && (c->mstate.cmd_flags & CMD_READONLY));
diff --git a/src/server.h b/src/server.h
index 2d572478f..f6e3b2009 100644
--- a/src/server.h
+++ b/src/server.h
@@ -2864,6 +2864,7 @@ int zslLexValueLteMax(sds value, zlexrangespec *spec);
int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level);
size_t freeMemoryGetNotCountedMemory();
int overMaxmemoryAfterAlloc(size_t moremem);
+uint64_t getCommandFlags(client *c);
int processCommand(client *c);
int processPendingCommandAndInputBuffer(client *c);
void setupSignalHandlers(void);
diff --git a/tests/unit/moduleapi/misc.tcl b/tests/unit/moduleapi/misc.tcl
index e9efdc2b3..04618ab89 100644
--- a/tests/unit/moduleapi/misc.tcl
+++ b/tests/unit/moduleapi/misc.tcl
@@ -173,6 +173,29 @@ start_server {tags {"modules"}} {
r config set maxmemory 0
} {OK} {needs:config-maxmemory}
+ test {rm_call OOM Eval} {
+ r config set maxmemory 1
+ r config set maxmemory-policy volatile-lru
+
+ # use the M flag without allow-oom shebang flag
+ assert_error {OOM *} {
+ r test.rm_call_flags M eval {#!lua
+ redis.call('set','x',1)
+ return 1
+ } 1 x
+ }
+
+ # add the M flag with allow-oom shebang flag
+ assert_equal {1} [
+ r test.rm_call_flags M eval {#!lua flags=allow-oom
+ redis.call('set','x',1)
+ return 1
+ } 1 x
+ ]
+
+ r config set maxmemory 0
+ } {OK} {needs:config-maxmemory}
+
test {rm_call write flag} {
# add the W flag
assert_error {ERR Write command 'set' was called while write is not allowed.} {