This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-nanoarrow.git
The following commit(s) were added to refs/heads/main by this push:
new b896d19e fix: allow null data for empty binary and string views during
append (#940)
b896d19e is described below
commit b896d19e4afc0b519bec808003257cf24bf3ebe9
Author: Fredrik Fornwall <[email protected]>
AuthorDate: Sat Sep 12 04:57:10 2026 +0200
fix: allow null data for empty binary and string views during append (#940)
[ArrowBufferView](https://arrow.apache.org/nanoarrow/latest/reference/c.html#_CPPv4N15ArrowBufferView4dataE)
and
[ArrowStringView](https://arrow.apache.org/nanoarrow/latest/reference/c.html#_CPPv4N15ArrowStringView4dataE)
allow a null data pointer when their size is zero:
> If size_bytes is 0, this value may be NULL.
Appending these views to binary-view or string-view arrays currently
passes the null pointer to `memcpy`, which is undefined behaviour even
for a zero-byte copy as flagged by UBSan.
Skip the inline copy for empty values to fix that.
Signed-off-by: Fredrik Fornwall <[email protected]>
---
src/nanoarrow/common/array_test.cc | 24 ++++++++++++++++++++++++
src/nanoarrow/common/inline_array.h | 4 +++-
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/src/nanoarrow/common/array_test.cc
b/src/nanoarrow/common/array_test.cc
index 4bb3cd95..1b0d1290 100644
--- a/src/nanoarrow/common/array_test.cc
+++ b/src/nanoarrow/common/array_test.cc
@@ -1193,6 +1193,30 @@ TEST(ArrayTest, ArrayTestAppendToStringViewArray) {
});
};
+TEST(ArrayTest, ArrayTestAppendNullDataToViewArray) {
+ for (enum ArrowType arrow_type :
+ {NANOARROW_TYPE_BINARY_VIEW, NANOARROW_TYPE_STRING_VIEW}) {
+ SCOPED_TRACE(ArrowTypeString(arrow_type));
+ nanoarrow::UniqueArray array;
+ ASSERT_EQ(ArrowArrayInitFromType(array.get(), arrow_type), NANOARROW_OK);
+ ASSERT_EQ(ArrowArrayStartAppending(array.get()), NANOARROW_OK);
+
+ // Empty buffer and string views may have a null data pointer.
+ // Run with UBSan to detect passing these pointers to memcpy, even with
size 0.
+ ASSERT_EQ(ArrowArrayAppendBytes(array.get(), {{nullptr}, 0}),
NANOARROW_OK);
+ ASSERT_EQ(ArrowArrayAppendString(array.get(), ArrowCharView(nullptr)),
NANOARROW_OK);
+ ASSERT_EQ(ArrowArrayFinishBuildingDefault(array.get(), nullptr),
NANOARROW_OK);
+
+ EXPECT_EQ(array->length, 2);
+ EXPECT_EQ(array->null_count, 0);
+ auto inline_buffer =
+ reinterpret_cast<const union ArrowBinaryView*>(array->buffers[1]);
+ for (int64_t i = 0; i < array->length; i++) {
+ EXPECT_EQ(inline_buffer[i].inlined.size, 0);
+ }
+ }
+}
+
TEST(ArrayTest, ArrayTestAppendToFixedSizeBinaryArray) {
struct ArrowArray array;
struct ArrowSchema schema;
diff --git a/src/nanoarrow/common/inline_array.h
b/src/nanoarrow/common/inline_array.h
index 885276b4..9bfc6dbd 100644
--- a/src/nanoarrow/common/inline_array.h
+++ b/src/nanoarrow/common/inline_array.h
@@ -589,7 +589,9 @@ static inline ArrowErrorCode ArrowArrayAppendBytes(struct
ArrowArray* array,
bvt.inlined.size = (int32_t)value.size_bytes;
if (value.size_bytes <= NANOARROW_BINARY_VIEW_INLINE_SIZE) {
- memcpy(bvt.inlined.data, value.data.as_char, value.size_bytes);
+ if (value.size_bytes > 0) {
+ memcpy(bvt.inlined.data, value.data.as_char, value.size_bytes);
+ }
memset(bvt.inlined.data + bvt.inlined.size, 0,
NANOARROW_BINARY_VIEW_INLINE_SIZE - bvt.inlined.size);
} else {