java-topology/defects/cfengine/patch/cfe-0001-getindices-stringset.patch

47 lines
1.9 KiB
Diff

# UNDF: UNDF-2026-000000027
diff --git a/libpromises/evalfunction.c b/libpromises/evalfunction.c
index a1b2c3d..e4f5a6b 100644
--- a/libpromises/evalfunction.c
+++ b/libpromises/evalfunction.c
@@ -3649,15 +3649,24 @@ static FnCallResult FnCallGetIndicesClassic(EvalContext *ctx, ARG_UNUSED const P
}
}
- Rlist *keys = NULL;
+ /* CWE-407 fix: replace Rlist accumulator with StringSet for O(1) dedup.
+ * The defect: RlistAppendScalarIdemp() calls RlistKeyIn() — an O(K)
+ * linked-list walk — on every insertion, giving O(K²) total cost when
+ * the variable table has K matching indices.
+ * Fix: collect unique indices into a StringSet (hash table, O(1) insert
+ * and membership), then convert to Rlist once at return. O(K) total. */
+ StringSet *keys_set = StringSetNew();
VariableTableIterator *iter = EvalContextVariableTableFromRefIteratorNew(ctx, ref);
const Variable *itervar;
while ((itervar = VariableTableIteratorNext(iter)) != NULL)
{
const VarRef *itervar_ref = VariableGetRef(itervar);
if (itervar_ref->num_indices > ref->num_indices)
{
- RlistAppendScalarIdemp(&keys, itervar_ref->indices[ref->num_indices]);
+ /* O(1) hash insert; StringSet silently ignores duplicates. */
+ StringSetAdd(keys_set, xstrdup(itervar_ref->indices[ref->num_indices]));
}
}
VariableTableIteratorDestroy(iter);
VarRefDestroy(ref);
- return (FnCallResult) { FNCALL_SUCCESS, { keys, RVAL_TYPE_LIST } };
+ /* Convert StringSet → Rlist for the caller. */
+ Rlist *keys = NULL;
+ StringSetIterator set_iter = StringSetIteratorInit(keys_set);
+ const char *key;
+ while ((key = StringSetIteratorNext(&set_iter)) != NULL)
+ {
+ RlistAppendScalar(&keys, key);
+ }
+ StringSetDestroy(keys_set);
+
+ return (FnCallResult) { FNCALL_SUCCESS, { keys, RVAL_TYPE_LIST } };
}