diff --git a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc index 8e7b626837fe..7fb069ef4256 100644 --- a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc +++ b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc @@ -2642,7 +2642,11 @@ struct SliceBytesTransform : StringSliceTransformBase { // on the resulting slice lengths, so return a worst case estimate. return input_bytes; } - int64_t max_slice_bytes = (opt.stop - opt.start + opt.step - 1) / opt.step; + // SliceOptions uses INT64_MIN/MAX for open-ended bounds. Clamp both bounds + // before arithmetic so equivalent out-of-range indices cannot overflow the size estimate. + const int64_t start = std::clamp(opt.start, -input_bytes, input_bytes); + const int64_t stop = std::clamp(opt.stop, -input_bytes, input_bytes); + int64_t max_slice_bytes = (stop - start + opt.step - 1) / opt.step; return std::min(input_bytes, ninputs * std::max(0, max_slice_bytes)); } diff --git a/cpp/src/arrow/compute/kernels/scalar_string_test.cc b/cpp/src/arrow/compute/kernels/scalar_string_test.cc index 74650c1d76c5..340a5efba177 100644 --- a/cpp/src/arrow/compute/kernels/scalar_string_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_string_test.cc @@ -2702,6 +2702,19 @@ TYPED_TEST(TestBinaryKernels, SliceBytesBasic) { } TYPED_TEST(TestBinaryKernels, SliceBytesPosPos) { + constexpr auto max = std::numeric_limits::max(); + SliceOptions options_default_stop{/*start=*/1}; + const std::string long_input(300, 'x'); + this->CheckUnary( + "binary_slice", this->template MakeArray({"abcdef", long_input}), + this->template MakeArray({"bcdef", std::string(299, 'x')}), + &options_default_stop); + SliceOptions options_default_stop_step{/*start=*/1, /*stop=*/max, /*step=*/5}; + this->CheckUnary("binary_slice", + this->template MakeArray({"abcdef", long_input}), + this->template MakeArray({"b", std::string(60, 'x')}), + &options_default_stop_step); + SliceOptions options{2, 4}; this->CheckUnary( "binary_slice", @@ -2748,6 +2761,23 @@ TYPED_TEST(TestBinaryKernels, SliceBytesPosNeg) { } TYPED_TEST(TestBinaryKernels, SliceBytesNegNeg) { + constexpr auto min = std::numeric_limits::min(); + const std::string long_input(300, 'x'); + SliceOptions options_extreme_start{/*start=*/min, /*stop=*/-1}; + this->CheckUnary("binary_slice", this->template MakeArray({"x"}), + this->template MakeArray({""}), + &options_extreme_start); + + SliceOptions options_min{/*start=*/-1, /*stop=*/min}; + this->CheckUnary("binary_slice", + this->template MakeArray({"abcdef", long_input}), + this->template MakeArray({"", ""}), &options_min); + SliceOptions options_min_step_neg{/*start=*/-1, /*stop=*/min, /*step=*/-5}; + this->CheckUnary("binary_slice", + this->template MakeArray({"abcdef", long_input}), + this->template MakeArray({"fa", std::string(60, 'x')}), + &options_min_step_neg); + SliceOptions options{-2, -1}; this->CheckUnary( "binary_slice",