diff --git a/vortex-buffer/src/bit/ops.rs b/vortex-buffer/src/bit/ops.rs index 7f07a39515a..9dbff9d4e2b 100644 --- a/vortex-buffer/src/bit/ops.rs +++ b/vortex-buffer/src/bit/ops.rs @@ -8,12 +8,9 @@ use crate::trusted_len::TrustedLenExt; #[inline] pub(super) fn bitwise_unary_op u64>(buffer: &BitBuffer, op: F) -> BitBuffer { - let iter = buffer.unaligned_chunks().iter().map(op); - let iter = unsafe { iter.trusted_len() }; - - let result = Buffer::::from_trusted_len_iter(iter).into_byte_buffer(); - - BitBuffer::new_with_offset(result, buffer.len(), buffer.offset()) + let mut buf = buffer.clone().into_mut(); + bitwise_unary_op_mut(&mut buf, op); + buf.freeze() } #[inline] @@ -89,6 +86,8 @@ pub(super) fn bitwise_binary_op u64>( #[cfg(test)] mod tests { + use std::ops::Not; + use super::*; use crate::bitbuffer; use crate::buffer; @@ -126,4 +125,26 @@ mod tests { let result = bitwise_binary_op(&left, &right, |l, r| l ^ r); assert_eq!(result, bitbuffer![false, true, true, false]); } + + /// Regression test for a bug where [`bitwise_unary_op`] produced corrupt results when + /// the [`BitBuffer`]'s underlying byte pointer was not u64-aligned. Slicing a buffer by + /// a non-multiple-of-8 number of bytes can cause this misalignment. The bug only + /// manifested for buffers larger than 16 bytes (> 128 bits), because Arrow's + /// `UnalignedBitChunk` switches from byte-copying to `align_to` at that threshold. + /// + /// Issue: + #[test] + fn test_bitwise_unary_not_misaligned_buffer() { + // Slice off 1 byte to shift the pointer off u64 alignment. Use 129 bits (17 bytes) + // to exceed the 16-byte threshold where `UnalignedBitChunk` uses `align_to`. + let padded = BitBuffer::new_set(8 + 129); + let buf = padded.slice(8..8 + 129); + + let result = buf.not(); + assert_eq!( + result.true_count(), + 0, + "expected all-false after NOT of all-true" + ); + } }