diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_string.cc b/cpp/src/arrow/compute/kernels/scalar_cast_string.cc index 52b79c8d452..babe17ced0d 100644 --- a/cpp/src/arrow/compute/kernels/scalar_cast_string.cc +++ b/cpp/src/arrow/compute/kernels/scalar_cast_string.cc @@ -367,8 +367,14 @@ BinaryToBinaryCastExec(KernelContext* ctx, const ExecSpan& batch, ExecResult* ou OffsetBuilder offset_builder(ctx->memory_pool()); RETURN_NOT_OK(offset_builder.Reserve(input.length + 1)); offset_builder.UnsafeAppend(0); // offsets start at 0 - const int64_t sum_of_binary_view_sizes = util::SumOfBinaryViewSizes( - input.GetValues(1), input.length); + // Null views are undefined and may hold any size, so only sum the valid ones + const auto* views = input.GetValues(1); + int64_t sum_of_binary_view_sizes = 0; + arrow::internal::VisitSetBitRunsVoid( + input.buffers[0].data, input.offset, input.length, + [&](int64_t position, int64_t length) { + sum_of_binary_view_sizes += util::SumOfBinaryViewSizes(views + position, length); + }); DataBuilder data_builder(ctx->memory_pool()); RETURN_NOT_OK(data_builder.Reserve(sum_of_binary_view_sizes)); VisitArraySpanInline( diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_test.cc b/cpp/src/arrow/compute/kernels/scalar_cast_test.cc index 864ec4afce0..9f593095531 100644 --- a/cpp/src/arrow/compute/kernels/scalar_cast_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_cast_test.cc @@ -3450,6 +3450,26 @@ TEST(Cast, StringToString) { } } +TEST(Cast, BinaryViewToBinaryNullViewSize) { + // Views under a null bit are undefined and may hold a negative size; it must + // not shrink the output data buffer. + auto json = R"(["foofoofoofoofoo", null, "barbarbarbarbarbarbar"])"; + for (auto from_type : {utf8_view(), binary_view()}) { + auto data = ArrayFromJSON(from_type, json)->data()->Copy(); + ASSERT_OK_AND_ASSIGN(data->buffers[1], + data->buffers[1]->CopySlice(0, data->buffers[1]->size())); + data->GetMutableValues(1)[1].inlined.size = -36; + auto from = MakeArray(data); + ASSERT_OK(from->ValidateFull()); + + for (auto to_type : {utf8(), large_utf8(), binary(), large_binary()}) { + ASSERT_OK_AND_ASSIGN(auto out, Cast(*from, to_type)); + ValidateOutput(*out); + AssertArraysEqual(*ArrayFromJSON(to_type, json), *out, /*verbose=*/true); + } + } +} + TEST(Cast, StringToStringWithOffset) { // GH-43660: Check casting String Arrays with nonzero offset std::vector offsets = {3, 8, 10, 12};