diff --git a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc index 8e7b626837fe..a743cb171899 100644 --- a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc +++ b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc @@ -2642,7 +2642,10 @@ 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 stop before + // arithmetic so equivalent out-of-range indices cannot overflow the size estimate. + const int64_t stop = std::clamp(opt.stop, -input_bytes, input_bytes); + int64_t max_slice_bytes = (stop - opt.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..733373c25d77 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,18 @@ TYPED_TEST(TestBinaryKernels, SliceBytesPosNeg) { } TYPED_TEST(TestBinaryKernels, SliceBytesNegNeg) { + constexpr auto min = std::numeric_limits::min(); + const std::string long_input(300, 'x'); + 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",