Redis模块RESTORE命令调用

时间:2018-05-25 12:06:39

标签: c redis segmentation-fault

我想将序列化密钥从文件恢复到模块中的redis内存。

以下是代码:

int Unarchive_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {

    if (argc != 2) {
        RedisModule_WrongArity(ctx);
    } else {

        RedisModuleString *keyName = argv[1];
        long long unarchiedKeys = 0;
        const char *filename = RedisModule_StringPtrLen(keyName, NULL);
        FILE *f = fopen(filename, "r");

        if (f != NULL && access(filename, F_OK) != -1) {

            struct stat info;

            if (stat(filename, &info) != 0) {

                RedisModule_ReplyWithError(ctx, "Error during file read");
            }

            size_t valueSize = info.st_size * sizeof(char);
            char *keyValue = RedisModule_Alloc(valueSize);
            fread(&keyValue, (size_t) info.st_size, 1, f);
            fclose(f);
            RedisModule_ReplyWithCallReply(ctx, RedisModule_Call(ctx, "RESTORE", "slbc", keyName, 0, keyValue, "REPLACE"));

            remove(filename);
            unarchiedKeys++;
        }

        RedisModule_ReplyWithLongLong(ctx, unarchiedKeys);
    }
    return REDISMODULE_OK;
}

当我运行此命令时,我在执行行SIGSEGV (Segmentation fault)

时得到RedisModule_ReplyWithCallReply(ctx, RedisModule_Call(ctx, "RESTORE", "slcc", keyName, 0, keyValue, "REPLACE"));

任何人都可以帮我解决这个问题吗?

提前致谢。

1 个答案:

答案 0 :(得分:1)

Segfaults 通常是通过取消引用空指针引起的,而空指针通常指向不属于进程地址空间的地址。这是一个很好的选择,这类问题是你的问题。一般来说,在使用变量之前,您似乎已经做了很好的验证变量,但有一些值得注意的例外:

  • 第一次使用ctx(除非argc计数错误,或stat != 0)正在调用RedisModule_ReplyWithCallReply。这应该 使用前请检查它是否为空。
  • 如果是RedisModule_Call的返回值,则无法检查 被称为另一个函数的参数。根据此 API documentation ,此函数为错误的回复类型返回NULL。

建议删除对RedisModule_Call的嵌入式调用,以便在将其作为参数传递给RedisModule_ReplyWithCallReply()之前测试它的返回值。

RedisModuleCallReply *reply = RedisModule_Call(ctx, "RESTORE", "slbc", keyName, 0, keyValue, valueSize, "REPLACE");
if(!reply)
{
   // handle error;
}
else
{
    RedisModule_ReplyWithCallReply(ctx, reply);
}

<强> 编辑:
另一个想法,一句话:

    fread(&keyValue, (size_t) info.st_size, 1, f);
          ^//not needed

应该是:

    fread(keyValue, (size_t) info.st_size, 1, f);