java-topology/defects/redis/patch/0001-sinter-listpack-promote-to-htset.patch

67 lines
2.7 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000260
From 2ba0194 Mon Sep 17 00:00:00 2001
Subject: [PATCH] t_set: promote listpack sets to temp dicts before SINTER loop
CWE-407: sinterGenericCommand performs O(N×M) membership checks when inner
sets use OBJ_ENCODING_LISTPACK. Each setTypeIsMemberAux call dispatches to
lpFind — an O(M) linear scan of the packed byte array. With the default
set-max-listpack-entries=128 this yields 128×128=16,384 comparisons per
SINTER instead of 128.
Fix: before the intersection loop, convert any LISTPACK-encoded inner set
(sets[1..setnum-1]) into a temporary OBJ_ENCODING_HT robj. Membership
checks become O(1) dictFind. The temporary objects are freed after the loop.
The smallest set (sets[0], iterated, never probed) is left as-is.
Also applies to the SDIFF algorithm-1 inner loop in sunionDiffGenericCommand.
--- a/src/t_set.c
+++ b/src/t_set.c
@@ -1383,6 +1383,7 @@ void sinterGenericCommand(client *c, robj **setkeys,
setTypeIterator si;
robj *dstset = NULL;
+ robj **tmp_ht = NULL; /* temp HT views of listpack inner sets */
char *str;
size_t len = 0;
int64_t intobj = 0;
@@ -1436,6 +1436,25 @@ void sinterGenericCommand(client *c, robj **setkeys,
*/
qsort(sets,setnum,sizeof(setopsrc),qsortCompareSetsByCardinality);
+ /* CWE-407 fix: promote listpack-encoded inner sets to temporary HT objects
+ * so membership checks inside the loop below are O(1) not O(n). */
+ if (setnum > 1) {
+ tmp_ht = zcalloc(setnum * sizeof(robj *));
+ for (j = 1; j < setnum; j++) {
+ if (sets[j].set && sets[j].set->encoding == OBJ_ENCODING_LISTPACK) {
+ robj *ht = createSetObject(); /* OBJ_ENCODING_HT */
+ setTypeIterator sit;
+ char *s; size_t slen; int64_t llv;
+ int enc;
+ setTypeInitIterator(&sit, sets[j].set);
+ while ((enc = setTypeNext(&sit, &s, &slen, &llv)) != -1) {
+ setTypeAddAux(ht, s, slen, llv, enc == OBJ_ENCODING_HT);
+ }
+ setTypeResetIterator(&sit);
+ tmp_ht[j] = ht;
+ sets[j].set = ht; /* redirect probe target */
+ }
+ }
+ }
+
/* The first thing we should output is the total number of elements...
@@ -1477,6 +1497,15 @@ void sinterGenericCommand(client *c, robj **setkeys,
}
setTypeResetIterator(&si);
+ /* Free temporary HT objects and restore original set pointers. */
+ if (tmp_ht) {
+ for (j = 1; j < setnum; j++) {
+ if (tmp_ht[j]) {
+ decrRefCount(tmp_ht[j]);
+ }
+ }
+ zfree(tmp_ht);
+ }
+
/* Update the key sizes histogram. */