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()) {

Reply via email to