From 1b2644cfd36ec2a67c88903f6102078cb4a90906 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 20 Jan 2026 22:18:25 +0400 Subject: [PATCH] fix: prevent multiplication overflow in search limit calculation --- src/core/db.rs | 31 ++++++++++++++++++++++++++++++- src/core/search.rs | 5 +++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/core/db.rs b/src/core/db.rs index 080e586..6bfd4d9 100644 --- a/src/core/db.rs +++ b/src/core/db.rs @@ -194,7 +194,9 @@ impl Database { .unwrap_or(std::cmp::Ordering::Equal) }); - results.truncate(limit * 3); // Get more for reranking + // Use saturating multiplication to prevent overflow + let effective_limit = limit.saturating_mul(3); + results.truncate(effective_limit); // Get more for reranking Ok(results) } @@ -303,3 +305,30 @@ fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 { (dot / (norm_a.sqrt() * norm_b.sqrt())) as f32 } + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + use std::panic::AssertUnwindSafe; + + #[test] + fn test_search_similar_overflow() { + let dir = tempdir().unwrap(); + let db_path = dir.path().join("test.db"); + let db = Database::new(&db_path).unwrap(); + + // Ensure checked_mul/saturating_mul is needed + let huge_limit = (usize::MAX / 3) + 1; + let query_embedding = vec![0.0; 10]; + let path = Path::new("/"); + + // This should NO LONGER panic + let db_ref = AssertUnwindSafe(&db); + let result = std::panic::catch_unwind(move || { + db_ref.search_similar(&query_embedding, path, huge_limit).unwrap(); + }); + + assert!(result.is_ok()); + } +} diff --git a/src/core/search.rs b/src/core/search.rs index 1690ba4..2dea427 100644 --- a/src/core/search.rs +++ b/src/core/search.rs @@ -45,10 +45,11 @@ impl SearchEngine { // Generate query embedding let query_embedding = self.embedding_engine.embed(query)?; - // Search for similar chunks + // Search for similar chunks with overflow protection + let limit = max_results.saturating_mul(3); let candidates = self .db - .search_similar(&query_embedding, &abs_path, max_results * 3)?; + .search_similar(&query_embedding, &abs_path, limit)?; if candidates.is_empty() { return Ok(Vec::new());