From 6dd213558b0f77e2233743718e23556fb06a557e Mon Sep 17 00:00:00 2001 From: sundb Date: Sun, 23 Oct 2022 01:36:50 +0800 Subject: Fix crash due to to reuse iterator entry after list deletion in module (#11383) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the module, we will reuse the list iterator entry for RM_ListDelete, but `listTypeDelete` will only update `quicklistEntry->zi` but not `quicklistEntry->node`, which will result in `quicklistEntry->node` pointing to a freed memory address if the quicklist node is deleted. This PR sync `key->u.list.index` and `key->u.list.entry` to list iterator after `RM_ListDelete`. This PR also optimizes the release code of the original list iterator. Co-authored-by: Viktor Söderqvist --- tests/modules/list.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'tests/modules') diff --git a/tests/modules/list.c b/tests/modules/list.c index 727b05d6f..401b2d802 100644 --- a/tests/modules/list.c +++ b/tests/modules/list.c @@ -50,7 +50,8 @@ int list_getall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { * The number of occurrences of "i" and "r" in cmdstr) should correspond to the * number of args after cmdstr. * - * The reply is the number of edits (inserts + replaces + deletes) performed. + * Reply with a RESP3 Map, containing the number of edits (inserts, replaces, deletes) + * performed, as well as the last index and the entry it points to. */ int list_edit(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc < 3) return RedisModule_WrongArity(ctx); @@ -92,7 +93,7 @@ int list_edit(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { } /* Iterate over the chars in cmdstr (edit instructions) */ - long long num_edits = 0; + long long num_inserts = 0, num_deletes = 0, num_replaces = 0; long index = reverse ? -1 : 0; RedisModuleString *value; @@ -102,17 +103,17 @@ int list_edit(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { value = argv[argpos++]; assert(RedisModule_ListInsert(key, index, value) == REDISMODULE_OK); index += reverse ? -1 : 1; - num_edits++; + num_inserts++; break; case 'd': /* delete */ assert(RedisModule_ListDelete(key, index) == REDISMODULE_OK); - num_edits++; + num_deletes++; break; case 'r': /* replace */ value = argv[argpos++]; assert(RedisModule_ListSet(key, index, value) == REDISMODULE_OK); index += reverse ? -1 : 1; - num_edits++; + num_replaces++; break; case 'k': /* keep */ index += reverse ? -1 : 1; @@ -120,7 +121,22 @@ int list_edit(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { } } - RedisModule_ReplyWithLongLong(ctx, num_edits); + RedisModuleString *v = RedisModule_ListGet(key, index); + RedisModule_ReplyWithMap(ctx, v ? 5 : 4); + RedisModule_ReplyWithCString(ctx, "i"); + RedisModule_ReplyWithLongLong(ctx, num_inserts); + RedisModule_ReplyWithCString(ctx, "d"); + RedisModule_ReplyWithLongLong(ctx, num_deletes); + RedisModule_ReplyWithCString(ctx, "r"); + RedisModule_ReplyWithLongLong(ctx, num_replaces); + RedisModule_ReplyWithCString(ctx, "index"); + RedisModule_ReplyWithLongLong(ctx, index); + if (v) { + RedisModule_ReplyWithCString(ctx, "entry"); + RedisModule_ReplyWithString(ctx, v); + RedisModule_FreeString(ctx, v); + } + RedisModule_CloseKey(key); return REDISMODULE_OK; } -- cgit v1.2.1