This is an automated email from the ASF dual-hosted git repository.
pitrou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new a8556b5e3c GH-51210: [C++] Initialize `output_` on empty `select_k`
inputs (#51212)
a8556b5e3c is described below
commit a8556b5e3cbdfc4d43ddc9af398e488271ab7b3f
Author: Alexander Taepper <[email protected]>
AuthorDate: Mon Sep 14 15:11:50 2026 +0200
GH-51210: [C++] Initialize `output_` on empty `select_k` inputs (#51212)
### Rationale for this change
This fixes possible crashes of `SelectKUnstable` if inputs were empty
### What changes are included in this PR?
This includes the bug fix and test cases which cover the broken prior
behavior.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
**This PR contains a "Critical Fix".**:
(c) a bug that causes a crash
If `SelectKUnstable` is called on an empty table or chunked-array the
process terminates with the exception `std::bad_variant_access`.
Through python, the wrapping of the (invalid) Datum in a python object
already fails with the following error message:
```
ValueError: Unable to wrap Datum in a Python object
```
* GitHub Issue: #51210
Authored-by: Alexander Taepper <[email protected]>
Signed-off-by: Antoine Pitrou <[email protected]>
---
cpp/src/arrow/compute/kernels/select_k_test.cc | 34 ++++++++++++++++++++++++
cpp/src/arrow/compute/kernels/vector_select_k.cc | 6 +++++
2 files changed, 40 insertions(+)
diff --git a/cpp/src/arrow/compute/kernels/select_k_test.cc
b/cpp/src/arrow/compute/kernels/select_k_test.cc
index 47e4af5800..3ed21dd488 100644
--- a/cpp/src/arrow/compute/kernels/select_k_test.cc
+++ b/cpp/src/arrow/compute/kernels/select_k_test.cc
@@ -415,6 +415,21 @@ TYPED_TEST(TestSelectKWithChunkedArrayTyped,
RandomValuesWithSlices) {
}
}
+TEST_F(TestSelectKWithChunkedArray, EmptyChunkedArray) {
+ auto chunked_array = std::make_shared<ChunkedArray>(ArrayVector{}, uint8());
+ ASSERT_EQ(chunked_array->num_chunks(), 0);
+ ASSERT_EQ(chunked_array->length(), 0);
+
+ for (const auto& options :
+ {SelectKOptions::TopKDefault(3), SelectKOptions::BottomKDefault(3),
+ SelectKOptions::TopKDefault(0)}) {
+ ASSERT_OK_AND_ASSIGN(auto indices, SelectKUnstable(Datum(*chunked_array),
options));
+ ASSERT_NE(indices, nullptr);
+ ValidateOutput(*indices);
+ ASSERT_EQ(indices->length(), 0);
+ }
+}
+
TEST_F(TestSelectKWithChunkedArray, PartialSelectKNull) {
auto chunked_array = std::vector<std::string>{
"[null, 1]",
@@ -1103,6 +1118,25 @@ struct TestSelectKWithTable : public ::testing::Test {
}
};
+TEST_F(TestSelectKWithTable, EmptyTable) {
+ auto schema = ::arrow::schema({
+ {field("a", uint8())},
+ {field("b", uint32())},
+ });
+ std::vector<std::string> input = {R"([])"};
+ auto table = TableFromJSON(schema, input);
+ ASSERT_EQ(table->num_rows(), 0);
+
+ for (const auto& options :
+ {SelectKOptions::TopKDefault(3, {"a"}),
SelectKOptions::BottomKDefault(3, {"a"}),
+ SelectKOptions::TopKDefault(0, {"a"})}) {
+ ASSERT_OK_AND_ASSIGN(auto indices, SelectKUnstable(Datum(*table),
options));
+ ASSERT_NE(indices, nullptr);
+ ValidateOutput(*indices);
+ ASSERT_EQ(indices->length(), 0);
+ }
+}
+
TEST_F(TestSelectKWithTable, TopKOneColumnKey) {
auto schema = ::arrow::schema({
{field("a", uint8())},
diff --git a/cpp/src/arrow/compute/kernels/vector_select_k.cc
b/cpp/src/arrow/compute/kernels/vector_select_k.cc
index 7d94fa2ba3..7a63c76f4e 100644
--- a/cpp/src/arrow/compute/kernels/vector_select_k.cc
+++ b/cpp/src/arrow/compute/kernels/vector_select_k.cc
@@ -274,6 +274,9 @@ class ChunkedArraySelector : public TypeVisitor {
const auto num_chunks = chunked_array_.num_chunks();
if (num_chunks == 0) {
+ ARROW_ASSIGN_OR_RAISE(auto take_indices,
+ MakeMutableUInt64Array(0, ctx_->memory_pool()));
+ *output_ = Datum(take_indices);
return Status::OK();
}
if (k_ > chunked_array_.length()) {
@@ -624,6 +627,9 @@ class TableSelector : public TypeVisitor {
const auto num_rows = table_.num_rows();
if (num_rows == 0) {
+ ARROW_ASSIGN_OR_RAISE(auto take_indices,
+ MakeMutableUInt64Array(0, ctx_->memory_pool()));
+ *output_ = Datum(take_indices);
return Status::OK();
}
if (k_ > table_.num_rows()) {