mirror of
https://github.com/redis/redis.git
synced 2026-05-28 04:02:46 -04:00
Fix memory leak in ZDIFF algorithm 2 on early exit (#14932)
Some checks failed
CI / test-ubuntu-latest (push) Has been cancelled
CI / test-sanitizer-address (push) Has been cancelled
CI / build-debian-old (push) Has been cancelled
CI / build-macos-latest (push) Has been cancelled
CI / build-32bit (push) Has been cancelled
CI / build-libc-malloc (push) Has been cancelled
CI / build-centos-jemalloc (push) Has been cancelled
CI / build-old-chain-jemalloc (push) Has been cancelled
Codecov / code-coverage (push) Has been cancelled
External Server Tests / test-external-standalone (push) Has been cancelled
External Server Tests / test-external-cluster (push) Has been cancelled
External Server Tests / test-external-nodebug (push) Has been cancelled
Spellcheck / Spellcheck (push) Has been cancelled
Some checks failed
CI / test-ubuntu-latest (push) Has been cancelled
CI / test-sanitizer-address (push) Has been cancelled
CI / build-debian-old (push) Has been cancelled
CI / build-macos-latest (push) Has been cancelled
CI / build-32bit (push) Has been cancelled
CI / build-libc-malloc (push) Has been cancelled
CI / build-centos-jemalloc (push) Has been cancelled
CI / build-old-chain-jemalloc (push) Has been cancelled
Codecov / code-coverage (push) Has been cancelled
External Server Tests / test-external-standalone (push) Has been cancelled
External Server Tests / test-external-cluster (push) Has been cancelled
External Server Tests / test-external-nodebug (push) Has been cancelled
Spellcheck / Spellcheck (push) Has been cancelled
## Problem `zdiffAlgorithm2()` can break out early once the destination cardinality reaches zero. In that path, a temporary SDS created by `zuiSdsFromValue()` is left dirty and never released, because the cleanup normally happens on the next `zuiNext()` call which is skipped due to the early `break`. `zuiClearIterator()` called after the loop does **not** clean up dirty values — only `zuiNext()` or explicit `zuiDiscardDirtyValue()` does. ## Fix Add `zuiDiscardDirtyValue(&zval)` before the early `break` to ensure the temporary SDS is freed on all exit paths.
This commit is contained in:
parent
8e89e0b89f
commit
2ba0194fbe
2 changed files with 16 additions and 1 deletions
|
|
@ -2793,7 +2793,10 @@ static void zdiffAlgorithm2(zsetopsrc *src, long setnum, zset *dstzset, size_t *
|
|||
|
||||
/* Exit if result set is empty as any additional removal
|
||||
* of elements will have no effect. */
|
||||
if (cardinality == 0) break;
|
||||
if (cardinality == 0) {
|
||||
zuiDiscardDirtyValue(&zval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
zuiClearIterator(&src[j]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1114,6 +1114,18 @@ start_server {tags {"zset"}} {
|
|||
assert_equal {a 1 e 5} [r zrange zsete{t} 0 -1 withscores]
|
||||
}
|
||||
|
||||
test "ZDIFF algorithm 2 empty result early exit - $encoding" {
|
||||
# Force algorithm 2 by inflating setnum with non-existing keys.
|
||||
# algo_one_work = len(src[0]) * setnum / 2 = 2 * 10 / 2 = 10
|
||||
# algo_two_work = 2 + 2 + 0*8 = 4
|
||||
# algo_one (10) > algo_two (4) -> algorithm 2 is selected
|
||||
r del zseta{t} zsetb{t} zsetc{t}
|
||||
r zadd zseta{t} 1 a 2 b
|
||||
r zadd zsetb{t} 1 a 2 b
|
||||
assert_equal 0 [r zdiffstore zsetc{t} 10 zseta{t} zsetb{t} nx1{t} nx2{t} nx3{t} nx4{t} nx5{t} nx6{t} nx7{t} nx8{t}]
|
||||
assert_equal {} [r zrange zsetc{t} 0 -1 withscores]
|
||||
}
|
||||
|
||||
test "ZDIFF fuzzing - $encoding" {
|
||||
for {set j 0} {$j < 100} {incr j} {
|
||||
unset -nocomplain s
|
||||
|
|
|
|||
Loading…
Reference in a new issue