Skip to content

Commit

Permalink
fix wrong data type conversion in zrangeResultBeginStore (#13148)
Browse files Browse the repository at this point in the history
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 <pingxie@google.com>
  • Loading branch information
lyq2333 authored and PingXie committed Jul 1, 2024
1 parent 4d5420e commit ce20cc2
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/t_zset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions tests/unit/type/zset.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ce20cc2

Please sign in to comment.