From 6b7b1f43a4f99411a96d5c2542e6db542305ef0f Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 31 Jul 2025 20:03:35 +0530 Subject: [PATCH 1/5] ensure f32 slice view is properly aligned and sized --- core/vector/vector_types.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/core/vector/vector_types.rs b/core/vector/vector_types.rs index 2ec79ed1d..7f4360174 100644 --- a/core/vector/vector_types.rs +++ b/core/vector/vector_types.rs @@ -25,8 +25,33 @@ pub struct Vector { } impl Vector { + /// # Safety + /// + /// This method is used to reinterpret the underlying `Vec` data + /// as a `&[f32]` slice. This is only valid if: + /// - The buffer is correctly aligned for `f32` + /// - The length of the buffer is exactly `dims * size_of::()` pub fn as_f32_slice(&self) -> &[f32] { - unsafe { std::slice::from_raw_parts(self.data.as_ptr() as *const f32, self.dims) } + if self.dims == 0 { + return &[]; + } + + assert_eq!( + self.data.len(), + self.dims * std::mem::size_of::(), + "data length must equal dims * size_of::()" + ); + + let ptr = self.data.as_ptr(); + let align = std::mem::align_of::(); + assert_eq!( + ptr.align_offset(align), + 0, + "data pointer must be aligned to {} bytes for f32 access", + align + ); + + unsafe { std::slice::from_raw_parts(ptr as *const f32, self.dims) } } pub fn as_f64_slice(&self) -> &[f64] { From 09542c9be075f2f9210e3e14c9e3f4deb5bfcd81 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 31 Jul 2025 20:04:00 +0530 Subject: [PATCH 2/5] ensure f64 slice view is properly aligned and sized --- core/vector/vector_types.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/core/vector/vector_types.rs b/core/vector/vector_types.rs index 7f4360174..37bc13731 100644 --- a/core/vector/vector_types.rs +++ b/core/vector/vector_types.rs @@ -54,7 +54,32 @@ impl Vector { unsafe { std::slice::from_raw_parts(ptr as *const f32, self.dims) } } + /// # Safety + /// + /// This method is used to reinterpret the underlying `Vec` data + /// as a `&[f64]` slice. This is only valid if: + /// - The buffer is correctly aligned for `f64` + /// - The length of the buffer is exactly `dims * size_of::()` pub fn as_f64_slice(&self) -> &[f64] { + if self.dims == 0 { + return &[]; + } + + assert_eq!( + self.data.len(), + self.dims * std::mem::size_of::(), + "data length must equal dims * size_of::()" + ); + + let ptr = self.data.as_ptr(); + let align = std::mem::align_of::(); + assert_eq!( + ptr.align_offset(align), + 0, + "data pointer must be aligned to {} bytes for f64 access", + align + ); + unsafe { std::slice::from_raw_parts(self.data.as_ptr() as *const f64, self.dims) } } } From 78d291b73f5734be88ac07efd7e407c38738cffd Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 31 Jul 2025 20:05:09 +0530 Subject: [PATCH 3/5] assert empty vector concat returns empty vector --- core/vector/vector_types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/vector/vector_types.rs b/core/vector/vector_types.rs index 37bc13731..f1edab2da 100644 --- a/core/vector/vector_types.rs +++ b/core/vector/vector_types.rs @@ -756,6 +756,7 @@ mod tests { let v2 = float32_vec_from(&[]); let result = vector_concat(&v1, &v2).unwrap(); assert_eq!(result.dims, 0); + assert_eq!(f32_slice_from_vector(&result), vec![]); } #[test] From a3d3a21030b82070a2b8e576f098d4c7a21edc6d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 31 Jul 2025 20:06:01 +0530 Subject: [PATCH 4/5] allow empty vector blobs by removing is_empty check in vector_type --- core/vector/vector_types.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/vector/vector_types.rs b/core/vector/vector_types.rs index f1edab2da..c0c4cd4a2 100644 --- a/core/vector/vector_types.rs +++ b/core/vector/vector_types.rs @@ -331,11 +331,6 @@ pub fn vector_f64_distance_cos(v1: &Vector, v2: &Vector) -> Result { } pub fn vector_type(blob: &[u8]) -> Result { - if blob.is_empty() { - return Err(LimboError::ConversionError( - "Invalid vector value".to_string(), - )); - } // Even-sized blobs are always float32. if blob.len() % 2 == 0 { return Ok(VectorType::Float32); From 86b72758ffdaad01d8d816c51672ee27785e9507 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 31 Jul 2025 20:39:04 +0530 Subject: [PATCH 5/5] fix clippy --- core/vector/vector_types.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/vector/vector_types.rs b/core/vector/vector_types.rs index c0c4cd4a2..779f1db86 100644 --- a/core/vector/vector_types.rs +++ b/core/vector/vector_types.rs @@ -47,8 +47,7 @@ impl Vector { assert_eq!( ptr.align_offset(align), 0, - "data pointer must be aligned to {} bytes for f32 access", - align + "data pointer must be aligned to {align} bytes for f32 access" ); unsafe { std::slice::from_raw_parts(ptr as *const f32, self.dims) } @@ -76,8 +75,7 @@ impl Vector { assert_eq!( ptr.align_offset(align), 0, - "data pointer must be aligned to {} bytes for f64 access", - align + "data pointer must be aligned to {align} bytes for f64 access" ); unsafe { std::slice::from_raw_parts(self.data.as_ptr() as *const f64, self.dims) } @@ -751,7 +749,7 @@ mod tests { let v2 = float32_vec_from(&[]); let result = vector_concat(&v1, &v2).unwrap(); assert_eq!(result.dims, 0); - assert_eq!(f32_slice_from_vector(&result), vec![]); + assert_eq!(f32_slice_from_vector(&result), Vec::::new()); } #[test]