diff --git a/cpp/src/arrow/compute/kernels/copy_data_internal.h b/cpp/src/arrow/compute/kernels/copy_data_internal.h index 735c2034c3f3..3dd8e14c6999 100644 --- a/cpp/src/arrow/compute/kernels/copy_data_internal.h +++ b/cpp/src/arrow/compute/kernels/copy_data_internal.h @@ -42,8 +42,10 @@ struct CopyDataUtils { static void CopyData(const DataType&, const ArraySpan& in, const int64_t in_offset, uint8_t* out, const int64_t out_offset, const int64_t length) { + // Boolean values are bit-packed, so apply the array's offset to the bit index + // rather than to the data pointer. const auto in_arr = in.GetValues(1, /*absolute_offset=*/0); - CopyData(*in.type, in_arr, in_offset, out, out_offset, length); + CopyData(*in.type, in_arr, in.offset + in_offset, out, out_offset, length); } }; diff --git a/cpp/src/arrow/compute/kernels/vector_replace_test.cc b/cpp/src/arrow/compute/kernels/vector_replace_test.cc index dc63bae39a54..65cb9126b15f 100644 --- a/cpp/src/arrow/compute/kernels/vector_replace_test.cc +++ b/cpp/src/arrow/compute/kernels/vector_replace_test.cc @@ -545,6 +545,14 @@ TEST_F(TestReplaceBoolean, ReplaceWithMask) { } } +TEST_F(TestReplaceBoolean, ReplaceWithMaskSlicedInput) { + auto input = + this->array("[true, false, null, true, true, false, null, true]")->Slice(3, 5); + + this->Assert(ReplaceWithMask, input, this->mask("[true, false, false, false, false]"), + this->array("[false]"), this->array("[false, true, false, null, true]")); +} + // Regression test: ReplaceMaskChunked (the ChunkedArray path of replace_with_mask) // sized each output chunk's data buffer via byte_width(), which is 0 for boolean // (bit-packed), the same GH-45086 buffer-overflow pattern fixed elsewhere in this @@ -2117,6 +2125,16 @@ TYPED_TEST(TestFillNullBinary, FillBackwardChunkedArray) { R"(["qup"])", R"(["qup", "mnz"])"})); } +TEST_F(TestFillNullBoolean, FillNullSlicedArray) { + auto input = + this->array("[true, false, null, true, true, false, null, true]")->Slice(3, 5); + + this->AssertFillNullArray(FillNullForward, input, + this->array("[true, true, false, false, true]")); + this->AssertFillNullArray(FillNullBackward, input, + this->array("[true, true, false, true, true]")); +} + // Regression test for GH-45086: FillNullForwardChunked/FillNullBackwardChunked // size each output chunk's data buffer as `type->byte_width() * chunk->length()`. // For BooleanType, byte_width() returns 0 (it is bit-packed, not byte-addressable),