mirror of https://mirror.osredm.com/root/redis.git
312 lines
14 KiB
C
312 lines
14 KiB
C
#include "redismodule.h"
|
|
|
|
#include <strings.h>
|
|
#include <sys/mman.h>
|
|
|
|
#define UNUSED(V) ((void) V)
|
|
|
|
void assertCrash(RedisModuleInfoCtx *ctx, int for_crash_report) {
|
|
UNUSED(ctx);
|
|
UNUSED(for_crash_report);
|
|
RedisModule_Assert(0);
|
|
}
|
|
|
|
void segfaultCrash(RedisModuleInfoCtx *ctx, int for_crash_report) {
|
|
UNUSED(ctx);
|
|
UNUSED(for_crash_report);
|
|
/* Compiler gives warnings about writing to a random address
|
|
* e.g "*((char*)-1) = 'x';". As a workaround, we map a read-only area
|
|
* and try to write there to trigger segmentation fault. */
|
|
char *p = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
*p = 'x';
|
|
}
|
|
|
|
int cmd_crash(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
|
UNUSED(ctx);
|
|
UNUSED(argv);
|
|
UNUSED(argc);
|
|
|
|
RedisModule_Assert(0);
|
|
return REDISMODULE_OK;
|
|
}
|
|
|
|
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
|
REDISMODULE_NOT_USED(argv);
|
|
REDISMODULE_NOT_USED(argc);
|
|
if (RedisModule_Init(ctx,"modulecrash",1,REDISMODULE_APIVER_1)
|
|
== REDISMODULE_ERR) return REDISMODULE_ERR;
|
|
|
|
if (argc >= 1) {
|
|
if (!strcasecmp(RedisModule_StringPtrLen(argv[0], NULL), "segfault")) {
|
|
if (RedisModule_RegisterInfoFunc(ctx, segfaultCrash) == REDISMODULE_ERR) return REDISMODULE_ERR;
|
|
} else if (!strcasecmp(RedisModule_StringPtrLen(argv[0], NULL),"assert")) {
|
|
if (RedisModule_RegisterInfoFunc(ctx, assertCrash) == REDISMODULE_ERR) return REDISMODULE_ERR;
|
|
}
|
|
}
|
|
|
|
/* Create modulecrash.xadd command which is similar to xadd command.
|
|
* It will crash in the command handler to verify we print command tokens
|
|
* when hide-user-data-from-log config is enabled */
|
|
RedisModuleCommandInfo info = {
|
|
.version = REDISMODULE_COMMAND_INFO_VERSION,
|
|
.arity = -5,
|
|
.key_specs = (RedisModuleCommandKeySpec[]){
|
|
{
|
|
.notes = "UPDATE instead of INSERT because of the optional trimming feature",
|
|
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE,
|
|
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX,
|
|
.bs.index.pos = 1,
|
|
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE,
|
|
.fk.range = {0,1,0}
|
|
},
|
|
{0}
|
|
},
|
|
.args = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "key",
|
|
.type = REDISMODULE_ARG_TYPE_KEY,
|
|
.key_spec_index = 0
|
|
},
|
|
{
|
|
.name = "nomkstream",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "NOMKSTREAM",
|
|
.since = "6.2.0",
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL
|
|
},
|
|
{
|
|
.name = "trim",
|
|
.type = REDISMODULE_ARG_TYPE_BLOCK,
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL,
|
|
.subargs = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "strategy",
|
|
.type = REDISMODULE_ARG_TYPE_ONEOF,
|
|
.subargs = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "maxlen",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "MAXLEN",
|
|
},
|
|
{
|
|
.name = "minid",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "MINID",
|
|
.since = "6.2.0",
|
|
},
|
|
{0}
|
|
}
|
|
},
|
|
{
|
|
.name = "operator",
|
|
.type = REDISMODULE_ARG_TYPE_ONEOF,
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL,
|
|
.subargs = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "equal",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "="
|
|
},
|
|
{
|
|
.name = "approximately",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "~"
|
|
},
|
|
{0}
|
|
}
|
|
},
|
|
{
|
|
.name = "threshold",
|
|
.type = REDISMODULE_ARG_TYPE_STRING,
|
|
.display_text = "threshold" /* Just for coverage, doesn't have a visible effect */
|
|
},
|
|
{
|
|
.name = "count",
|
|
.type = REDISMODULE_ARG_TYPE_INTEGER,
|
|
.token = "LIMIT",
|
|
.since = "6.2.0",
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL
|
|
},
|
|
{0}
|
|
}
|
|
},
|
|
{
|
|
.name = "id-selector",
|
|
.type = REDISMODULE_ARG_TYPE_ONEOF,
|
|
.subargs = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "auto-id",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "*"
|
|
},
|
|
{
|
|
.name = "id",
|
|
.type = REDISMODULE_ARG_TYPE_STRING,
|
|
},
|
|
{0}
|
|
}
|
|
},
|
|
{
|
|
.name = "data",
|
|
.type = REDISMODULE_ARG_TYPE_BLOCK,
|
|
.flags = REDISMODULE_CMD_ARG_MULTIPLE,
|
|
.subargs = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "field",
|
|
.type = REDISMODULE_ARG_TYPE_STRING,
|
|
},
|
|
{
|
|
.name = "value",
|
|
.type = REDISMODULE_ARG_TYPE_STRING,
|
|
},
|
|
{0}
|
|
}
|
|
},
|
|
{0}
|
|
}
|
|
};
|
|
|
|
RedisModuleCommand *cmd;
|
|
|
|
if (RedisModule_CreateCommand(ctx,"modulecrash.xadd", cmd_crash,"write deny-oom random fast",0,0,0) == REDISMODULE_ERR)
|
|
return REDISMODULE_ERR;
|
|
cmd = RedisModule_GetCommand(ctx,"modulecrash.xadd");
|
|
if (RedisModule_SetCommandInfo(cmd, &info) == REDISMODULE_ERR)
|
|
return REDISMODULE_ERR;
|
|
|
|
/* Create a subcommand: modulecrash.parent sub
|
|
* It will crash in the command handler to verify we print subcommand name
|
|
* when hide-user-data-from-log config is enabled */
|
|
RedisModuleCommandInfo subcommand_info = {
|
|
.version = REDISMODULE_COMMAND_INFO_VERSION,
|
|
.arity = -5,
|
|
.key_specs = (RedisModuleCommandKeySpec[]){
|
|
{
|
|
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE,
|
|
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX,
|
|
.bs.index.pos = 1,
|
|
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE,
|
|
.fk.range = {0,1,0}
|
|
},
|
|
{0}
|
|
},
|
|
.args = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "key",
|
|
.type = REDISMODULE_ARG_TYPE_KEY,
|
|
.key_spec_index = 0
|
|
},
|
|
{
|
|
.name = "token",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "TOKEN",
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL
|
|
},
|
|
{
|
|
.name = "data",
|
|
.type = REDISMODULE_ARG_TYPE_BLOCK,
|
|
.subargs = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "field",
|
|
.type = REDISMODULE_ARG_TYPE_STRING,
|
|
},
|
|
{
|
|
.name = "value",
|
|
.type = REDISMODULE_ARG_TYPE_STRING,
|
|
},
|
|
{0}
|
|
}
|
|
},
|
|
{0}
|
|
}
|
|
};
|
|
|
|
if (RedisModule_CreateCommand(ctx,"modulecrash.parent",NULL,"",0,0,0) == REDISMODULE_ERR)
|
|
return REDISMODULE_ERR;
|
|
|
|
RedisModuleCommand *parent = RedisModule_GetCommand(ctx,"modulecrash.parent");
|
|
|
|
if (RedisModule_CreateSubcommand(parent,"subcmd",cmd_crash,"",0,0,0) == REDISMODULE_ERR)
|
|
return REDISMODULE_ERR;
|
|
|
|
cmd = RedisModule_GetCommand(ctx,"modulecrash.parent|subcmd");
|
|
if (RedisModule_SetCommandInfo(cmd, &subcommand_info) == REDISMODULE_ERR)
|
|
return REDISMODULE_ERR;
|
|
|
|
/* Create modulecrash.zunion command which is similar to zunion command.
|
|
* It will crash in the command handler to verify we print command tokens
|
|
* when hide-user-data-from-log config is enabled */
|
|
RedisModuleCommandInfo zunioninfo = {
|
|
.version = REDISMODULE_COMMAND_INFO_VERSION,
|
|
.arity = -5,
|
|
.key_specs = (RedisModuleCommandKeySpec[]){
|
|
{
|
|
.flags = REDISMODULE_CMD_KEY_RO,
|
|
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX,
|
|
.bs.index.pos = 1,
|
|
.find_keys_type = REDISMODULE_KSPEC_FK_KEYNUM,
|
|
.fk.keynum = {0,1,1}
|
|
},
|
|
{0}
|
|
},
|
|
.args = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "numkeys",
|
|
.type = REDISMODULE_ARG_TYPE_INTEGER,
|
|
},
|
|
{
|
|
.name = "key",
|
|
.type = REDISMODULE_ARG_TYPE_KEY,
|
|
.key_spec_index = 0,
|
|
.flags = REDISMODULE_CMD_ARG_MULTIPLE
|
|
},
|
|
{
|
|
.name = "weights",
|
|
.type = REDISMODULE_ARG_TYPE_INTEGER,
|
|
.token = "WEIGHTS",
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL | REDISMODULE_CMD_ARG_MULTIPLE
|
|
},
|
|
{
|
|
.name = "aggregate",
|
|
.type = REDISMODULE_ARG_TYPE_ONEOF,
|
|
.token = "AGGREGATE",
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL,
|
|
.subargs = (RedisModuleCommandArg[]){
|
|
{
|
|
.name = "sum",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "sum"
|
|
},
|
|
{
|
|
.name = "min",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "min"
|
|
},
|
|
{
|
|
.name = "max",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "max"
|
|
},
|
|
{0}
|
|
}
|
|
},
|
|
{
|
|
.name = "withscores",
|
|
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN,
|
|
.token = "WITHSCORES",
|
|
.flags = REDISMODULE_CMD_ARG_OPTIONAL
|
|
},
|
|
{0}
|
|
}
|
|
};
|
|
|
|
if (RedisModule_CreateCommand(ctx,"modulecrash.zunion", cmd_crash,"readonly",0,0,0) == REDISMODULE_ERR)
|
|
return REDISMODULE_ERR;
|
|
cmd = RedisModule_GetCommand(ctx,"modulecrash.zunion");
|
|
if (RedisModule_SetCommandInfo(cmd, &zunioninfo) == REDISMODULE_ERR)
|
|
return REDISMODULE_ERR;
|
|
|
|
|
|
return REDISMODULE_OK;
|
|
}
|