From c8f1ec959aaeeea3eb81b3b95faba0a767ad6d87 Mon Sep 17 00:00:00 2001 From: ofiryanai Date: Mon, 24 Nov 2025 11:48:49 +0200 Subject: [PATCH] Limit VADD REDUCE dim to not exceed original dim * Limit VADD REDUCE dim to not exceed original dim Enforce VADD key [REDUCE dim] to reject dim that is bigger than the HNSW original dim, as dimension reduction makes no sense for reduce_dim > original_dim. This also avoids OOM and possible heap overflow on later allocations using reduce_dim. This should be backported to Redis version 8.0, 8.2 and 8.4. --- .../vector-sets/tests/dimension_validation.py | 30 +++++++++++++++++++ modules/vector-sets/vset.c | 6 ++++ 2 files changed, 36 insertions(+) diff --git a/modules/vector-sets/tests/dimension_validation.py b/modules/vector-sets/tests/dimension_validation.py index f0811529a2..7e13f57cf8 100644 --- a/modules/vector-sets/tests/dimension_validation.py +++ b/modules/vector-sets/tests/dimension_validation.py @@ -65,3 +65,33 @@ class DimensionValidation(TestCase): assert False, "VSIM with wrong dimension should fail" except redis.exceptions.ResponseError as e: assert "Input dimension mismatch for projection" in str(e), f"Expected dimension mismatch error in VSIM, got: {e}" + +class ReduceDimConstraintValidation(TestCase): + def getname(self): + return "[regression] VADD enforces reduce_dim <= dim" + + def estimated_runtime(self): + return 0.1 + + def test(self): + import struct + + dim = 16 + reduce_dim = dim + 1 # Intentionally larger than dim + + # Build a simple FP32 vector of the given dimension. + vec = [0.0] * dim + vec_bytes = struct.pack(f'{dim}f', *vec) + + try: + self.redis.execute_command( + 'VADD', self.test_key, + 'REDUCE', reduce_dim, + 'FP32', vec_bytes, + f'{self.test_key}:item:reducemismatch') + assert False, "VADD with reduce_dim > dim should fail" + except redis.exceptions.ResponseError as e: + # Same generic validation error path as other vector spec problems. + assert "invalid vector specification" in str(e), ( + f"Expected invalid vector error, got: {e}") + diff --git a/modules/vector-sets/vset.c b/modules/vector-sets/vset.c index b99a610caf..b3b47871b1 100644 --- a/modules/vector-sets/vset.c +++ b/modules/vector-sets/vset.c @@ -445,6 +445,12 @@ float *parseVector(RedisModuleString **argv, int argc, int start_idx, return NULL; // Unknown format. } + // reduce_dim must be <= dim + if (reduce_dim && *reduce_dim && *reduce_dim > *dim) { + if (vec) RedisModule_Free(vec); + return NULL; + } + if (consumed_args) *consumed_args = consumed; return vec; }