From ce20cc28019a8f2d49a2a1ed27d259033ff1af48 Mon Sep 17 00:00:00 2001 From: Yanqi Lv Date: Tue, 19 Mar 2024 14:52:55 +0800 Subject: [PATCH] fix wrong data type conversion in zrangeResultBeginStore (#13148) In `beginResultEmission`, -1 means the result length is not known in advance. But after #12185, if we pass -1 to `zrangeResultBeginStore`, it will convert to SIZE_MAX in `zsetTypeCreate` and try to `dictExpand`. Although `dictExpand` won't succeed because the size overflows, I think we'd better to avoid this wrong conversion. This bug can be triggered when the source of `zrangestore` doesn't exist or we use `zrangestore` command with `byscore` or `bylex`. The impact is that dst keys will be converted to use skiplist instead of listpack. Signed-off-by: Ping Xie --- src/t_zset.c | 5 +++-- tests/unit/type/zset.tcl | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/t_zset.c b/src/t_zset.c index 7717a4a14d..1b267e0e99 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -1172,7 +1172,8 @@ unsigned long zsetLength(const robj *zobj) { * and the value len hint indicates the approximate individual size of the added elements, * they are used to determine the initial representation. * - * If the hints are not known, and underestimation or 0 is suitable. */ + * If the hints are not known, and underestimation or 0 is suitable. + * We should never pass a negative value because it will convert to a very large unsigned number. */ robj *zsetTypeCreate(size_t size_hint, size_t val_len_hint) { if (size_hint <= server.zset_max_listpack_entries && val_len_hint <= server.zset_max_listpack_value) @@ -3001,7 +3002,7 @@ static void zrangeResultFinalizeClient(zrange_result_handler *handler, /* Result handler methods for storing the ZRANGESTORE to a zset. */ static void zrangeResultBeginStore(zrange_result_handler *handler, long length) { - handler->dstobj = zsetTypeCreate(length, 0); + handler->dstobj = zsetTypeCreate(length >= 0 ? length : 0, 0); } static void zrangeResultEmitCBufferForStore(zrange_result_handler *handler, diff --git a/tests/unit/type/zset.tcl b/tests/unit/type/zset.tcl index e84cb0e307..0a4278464a 100644 --- a/tests/unit/type/zset.tcl +++ b/tests/unit/type/zset.tcl @@ -2239,12 +2239,18 @@ start_server {tags {"zset"}} { } {b 2 c 3} test {ZRANGESTORE BYLEX} { + set res [r zrangestore z3{t} z1{t} \[b \[c BYLEX] + assert_equal $res 2 + assert_encoding listpack z3{t} set res [r zrangestore z2{t} z1{t} \[b \[c BYLEX] assert_equal $res 2 r zrange z2{t} 0 -1 withscores } {b 2 c 3} test {ZRANGESTORE BYSCORE} { + set res [r zrangestore z4{t} z1{t} 1 2 BYSCORE] + assert_equal $res 2 + assert_encoding listpack z4{t} set res [r zrangestore z2{t} z1{t} 1 2 BYSCORE] assert_equal $res 2 r zrange z2{t} 0 -1 withscores