Skip to content

Commit 7e4d069

Browse files
committed
handle null variadic buffers in C bridge
1 parent b4f0989 commit 7e4d069

2 files changed

Lines changed: 49 additions & 13 deletions

File tree

cpp/src/arrow/c/bridge.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -608,12 +608,8 @@ struct ArrayExporter {
608608
export_.variadic_buffer_sizes_.resize(variadic_buffers.size());
609609
size_t i = 0;
610610
for (const auto& buf : variadic_buffers) {
611-
if (buf == nullptr) {
612-
return Status::Invalid("Cannot export array of type ", data->type->ToString(),
613-
": null variadic buffer at buffer index #", i + 2,
614-
" (variadic buffer index #", i, ")");
615-
}
616-
export_.variadic_buffer_sizes_[i++] = buf->size();
611+
// The C Data Interface allows null variadic buffer pointers with size 0.
612+
export_.variadic_buffer_sizes_[i++] = buf == nullptr ? 0 : buf->size();
617613
}
618614
export_.buffers_.back() = export_.variadic_buffer_sizes_.data();
619615
}

cpp/src/arrow/c/bridge_test.cc

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,8 @@ TEST_F(TestArrayExport, PrimitiveSliced) {
930930
TestPrimitive(factory);
931931
}
932932

933-
TEST_F(TestArrayExport, RejectNullVariadicBuffers) {
933+
TEST_F(TestArrayExport, NullVariadicBuffers) {
934+
// GH-49740: _export_to_c segmentation fault for binary_view array.
934935
for (const auto& type : {binary_view(), utf8_view()}) {
935936
auto arr =
936937
MakeArray(ArrayData::Make(type, /*length=*/2,
@@ -942,12 +943,14 @@ TEST_F(TestArrayExport, RejectNullVariadicBuffers) {
942943
nullptr}));
943944

944945
struct ArrowArray c_export;
945-
EXPECT_RAISES_WITH_MESSAGE_THAT(
946-
Invalid,
947-
::testing::HasSubstr(
948-
"Cannot export array of type " + type->ToString() +
949-
": null variadic buffer at buffer index #2 (variadic buffer index #0)"),
950-
ExportArray(*arr, &c_export));
946+
ASSERT_OK(ExportArray(*arr, &c_export));
947+
ArrayExportGuard guard(&c_export);
948+
949+
ASSERT_EQ(c_export.n_buffers, 4);
950+
ASSERT_EQ(c_export.buffers[2], nullptr);
951+
ASSERT_NE(c_export.buffers[3], nullptr);
952+
const auto* variadic_buffer_sizes = static_cast<const int64_t*>(c_export.buffers[3]);
953+
ASSERT_EQ(variadic_buffer_sizes[0], 0);
951954
}
952955
}
953956

@@ -3017,6 +3020,43 @@ TEST_F(TestArrayImport, String) {
30173020
CheckImport(ArrayFromJSON(large_binary(), "[]"));
30183021
}
30193022

3023+
TEST_F(TestArrayImport, NullVariadicBuffers) {
3024+
// The C Data Interface allows null variadic buffer pointers with size 0.
3025+
// Import normalizes them to non-null zero-size buffers in Arrow C++.
3026+
std::vector<BinaryViewType::c_type> views = {
3027+
util::ToInlineBinaryView("hello"),
3028+
util::ToInlineBinaryView("world"),
3029+
};
3030+
constexpr int64_t null_variadic_buffer_sizes[] = {0};
3031+
const void* null_variadic_buffer[] = {
3032+
nullptr,
3033+
views.data(),
3034+
nullptr,
3035+
null_variadic_buffer_sizes,
3036+
};
3037+
3038+
for (const auto& type : {binary_view(), utf8_view()}) {
3039+
FillStringViewLike(/*length=*/2, /*null_count=*/0, /*offset=*/0, null_variadic_buffer,
3040+
/*data_buffer_count=*/1);
3041+
3042+
ArrayReleaseCallback cb(&c_struct_);
3043+
ASSERT_OK_AND_ASSIGN(auto array, ImportArray(&c_struct_, type));
3044+
ASSERT_TRUE(ArrowArrayIsReleased(&c_struct_));
3045+
Reset();
3046+
3047+
ASSERT_OK(array->ValidateFull());
3048+
AssertArraysEqual(*ArrayFromJSON(type, R"(["hello", "world"])"), *array,
3049+
/*verbose=*/true);
3050+
3051+
ASSERT_EQ(array->data()->buffers.size(), 3);
3052+
ASSERT_NE(array->data()->buffers[2], nullptr);
3053+
ASSERT_EQ(array->data()->buffers[2]->size(), 0);
3054+
cb.AssertNotCalled();
3055+
array.reset();
3056+
cb.AssertCalled();
3057+
}
3058+
}
3059+
30203060
TEST_F(TestArrayImport, StringWithOffset) {
30213061
FillStringLike(3, 0, 1, string_buffers_no_nulls1);
30223062
CheckImport(ArrayFromJSON(utf8(), R"(["", "bar", "quux"])"));

0 commit comments

Comments
 (0)