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 230cfd4  feat!: Allow explicit validation level in 
`ArrowArrayFinishBuilding()` (#175)
230cfd4 is described below

commit 230cfd497bc351c667523aaa288546e03b7d621f
Author: Dewey Dunnington <[email protected]>
AuthorDate: Wed Mar 29 12:12:39 2023 -0400

    feat!: Allow explicit validation level in `ArrowArrayFinishBuilding()` 
(#175)
    
    This is a breaking change! The signature of `ArrowArrayFinishBuilding()`
    gains a `validation_level` argument, and the original function was
    renamed to `ArrowArrayFinishBuildingDefault()`. I could do this in a
    non-breaking way but there are no non-awkward names for
    `ArrowArrayFinishBuildingWithExplicitValidationLevel()` and it seems
    more important to cultivate a quality API at this point rather than
    maintain full backward compatibility (plus it's a relatively easy rename
    fix).
    
    This adds two important features. First, it lets you preform more
    validation if you want to (via `NANOARROW_VALIDATION_LEVEL_FULL`,
    implemented with the just-added `ArrowArrayViewValidateFull()`). Second,
    it lets you perform less validation if you want to (e.g., if your
    buffers are sitting on a GPU and dereferencing a buffer value will
    crash).
---
 README.md                                          |   6 +-
 examples/cmake-minimal/src/library.c               |   4 +-
 examples/vendored-minimal/src/library.c            |   2 +-
 .../src/nanoarrow/nanoarrow_ipc_decoder.c          |   2 +-
 r/src/array.c                                      |   4 +-
 r/src/as_array.c                                   |  20 +--
 src/nanoarrow/array.c                              |  34 +++-
 src/nanoarrow/array_stream_test.cc                 |   6 +-
 src/nanoarrow/array_test.cc                        | 172 +++++++++++++++------
 src/nanoarrow/nanoarrow.h                          |  20 ++-
 src/nanoarrow/nanoarrow_hpp_test.cc                |   4 +-
 src/nanoarrow/nanoarrow_types.h                    |  19 +++
 12 files changed, 220 insertions(+), 73 deletions(-)

diff --git a/README.md b/README.md
index b411cd0..0c1c2bd 100644
--- a/README.md
+++ b/README.md
@@ -51,14 +51,14 @@ int make_simple_array(struct ArrowArray* array_out, struct 
ArrowSchema* schema_o
   array_out->release = NULL;
   schema_out->release = NULL;
 
-  NANOARROW_RETURN_NOT_OK(ArrowArrayInit(array_out, NANOARROW_TYPE_INT32));
+  NANOARROW_RETURN_NOT_OK(ArrowArrayInitFromType(array_out, 
NANOARROW_TYPE_INT32));
 
   NANOARROW_RETURN_NOT_OK(ArrowArrayStartAppending(array_out));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 1));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 2));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 3));
-  NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuilding(array_out, &error));
-  
+  NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuildingDefault(array_out, &error));
+
   NANOARROW_RETURN_NOT_OK(ArrowSchemaInit(schema_out, NANOARROW_TYPE_INT32));
 
   return NANOARROW_OK;
diff --git a/examples/cmake-minimal/src/library.c 
b/examples/cmake-minimal/src/library.c
index b44f9ec..ac16184 100644
--- a/examples/cmake-minimal/src/library.c
+++ b/examples/cmake-minimal/src/library.c
@@ -39,8 +39,8 @@ int make_simple_array(struct ArrowArray* array_out, struct 
ArrowSchema* schema_o
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 1));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 2));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 3));
-  NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuilding(array_out, &global_error));
-  
+  NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuildingDefault(array_out, 
&global_error));
+
   NANOARROW_RETURN_NOT_OK(ArrowSchemaInitFromType(schema_out, 
NANOARROW_TYPE_INT32));
 
   return NANOARROW_OK;
diff --git a/examples/vendored-minimal/src/library.c 
b/examples/vendored-minimal/src/library.c
index c1e634f..fe6f396 100644
--- a/examples/vendored-minimal/src/library.c
+++ b/examples/vendored-minimal/src/library.c
@@ -39,7 +39,7 @@ int make_simple_array(struct ArrowArray* array_out, struct 
ArrowSchema* schema_o
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 1));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 2));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 3));
-  NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuilding(array_out, &global_error));
+  NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuildingDefault(array_out, 
&global_error));
 
   NANOARROW_RETURN_NOT_OK(ArrowSchemaInitFromType(schema_out, 
NANOARROW_TYPE_INT32));
 
diff --git a/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc_decoder.c 
b/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc_decoder.c
index 2f9f845..db4169c 100644
--- a/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc_decoder.c
+++ b/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc_decoder.c
@@ -1381,7 +1381,7 @@ static ArrowErrorCode ArrowIpcDecoderDecodeArrayInternal(
   // TODO: this performs some validation but doesn't do everything we need it 
to do
   // notably it doesn't loop over offset buffers to look for values that will 
cause
   // out-of-bounds buffer access on the data buffer or child arrays.
-  result = ArrowArrayFinishBuilding(&temp, error);
+  result = ArrowArrayFinishBuildingDefault(&temp, error);
   if (result != NANOARROW_OK) {
     temp.release(&temp);
     return result;
diff --git a/r/src/array.c b/r/src/array.c
index 4e38c14..dce4a33 100644
--- a/r/src/array.c
+++ b/r/src/array.c
@@ -288,9 +288,9 @@ SEXP nanoarrow_c_array_validate_after_modify(SEXP 
array_xptr, SEXP schema_xptr)
     Rf_error("move_array_buffers: %s", error.message);
   }
 
-  result = ArrowArrayFinishBuilding(array_dst, &error);
+  result = ArrowArrayFinishBuildingDefault(array_dst, &error);
   if (result != NANOARROW_OK) {
-    Rf_error("ArrowArrayFinishBuilding(): %s", error.message);
+    Rf_error("ArrowArrayFinishBuildingDefault(): %s", error.message);
   }
 
   UNPROTECT(1);
diff --git a/r/src/as_array.c b/r/src/as_array.c
index 592e83b..6221d8e 100644
--- a/r/src/as_array.c
+++ b/r/src/as_array.c
@@ -109,9 +109,9 @@ static void as_array_int(SEXP x_sexp, struct ArrowArray* 
array, SEXP schema_xptr
   }
 
   array->null_count = null_count;
-  result = ArrowArrayFinishBuilding(array, error);
+  result = ArrowArrayFinishBuildingDefault(array, error);
   if (result != NANOARROW_OK) {
-    Rf_error("ArrowArrayFinishBuilding(): %s", error->message);
+    Rf_error("ArrowArrayFinishBuildingDefault(): %s", error->message);
   }
 }
 
@@ -187,9 +187,9 @@ static void as_array_lgl(SEXP x_sexp, struct ArrowArray* 
array, SEXP schema_xptr
   }
 
   array->null_count = null_count;
-  result = ArrowArrayFinishBuilding(array, error);
+  result = ArrowArrayFinishBuildingDefault(array, error);
   if (result != NANOARROW_OK) {
-    Rf_error("ArrowArrayFinishBuilding(): %s", error->message);
+    Rf_error("ArrowArrayFinishBuildingDefault(): %s", error->message);
   }
 }
 
@@ -312,9 +312,9 @@ static void as_array_dbl(SEXP x_sexp, struct ArrowArray* 
array, SEXP schema_xptr
   }
 
   array->null_count = null_count;
-  result = ArrowArrayFinishBuilding(array, error);
+  result = ArrowArrayFinishBuildingDefault(array, error);
   if (result != NANOARROW_OK) {
-    Rf_error("ArrowArrayFinishBuilding(): %s", error->message);
+    Rf_error("ArrowArrayFinishBuildingDefault(): %s", error->message);
   }
 }
 
@@ -397,9 +397,9 @@ static void as_array_chr(SEXP x_sexp, struct ArrowArray* 
array, SEXP schema_xptr
   }
 
   array->null_count = null_count;
-  result = ArrowArrayFinishBuilding(array, error);
+  result = ArrowArrayFinishBuildingDefault(array, error);
   if (result != NANOARROW_OK) {
-    Rf_error("ArrowArrayFinishBuilding(): %s", error->message);
+    Rf_error("ArrowArrayFinishBuildingDefault(): %s", error->message);
   }
 }
 
@@ -529,9 +529,9 @@ static void as_array_list(SEXP x_sexp, struct ArrowArray* 
array, SEXP schema_xpt
   }
 
   array->null_count = null_count;
-  result = ArrowArrayFinishBuilding(array, error);
+  result = ArrowArrayFinishBuildingDefault(array, error);
   if (result != NANOARROW_OK) {
-    Rf_error("ArrowArrayFinishBuilding(): %s", error->message);
+    Rf_error("ArrowArrayFinishBuildingDefault(): %s", error->message);
   }
 }
 
diff --git a/src/nanoarrow/array.c b/src/nanoarrow/array.c
index 81675bb..fc88fd6 100644
--- a/src/nanoarrow/array.c
+++ b/src/nanoarrow/array.c
@@ -435,14 +435,23 @@ static ArrowErrorCode ArrowArrayCheckInternalBufferSizes(
 }
 
 ArrowErrorCode ArrowArrayFinishBuilding(struct ArrowArray* array,
+                                        enum ArrowValidationLevel 
validation_level,
                                         struct ArrowError* error) {
-  // Even if the data buffer is size zero, the value needs to be non-null
-  NANOARROW_RETURN_NOT_OK(ArrowArrayFinalizeBuffers(array));
+  // Even if the data buffer is size zero, the pointer value needed to be 
non-null
+  // in some implementations (at least one version of Arrow C++ at the time 
this
+  // was added). Only do this fix if we can assume CPU data access.
+  if (validation_level >= NANOARROW_VALIDATION_LEVEL_DEFAULT) {
+    NANOARROW_RETURN_NOT_OK(ArrowArrayFinalizeBuffers(array));
+  }
 
   // Make sure the value we get with array->buffers[i] is set to the actual
   // pointer (which may have changed from the original due to reallocation)
   ArrowArrayFlushInternalPointers(array);
 
+  if (validation_level == NANOARROW_VALIDATION_LEVEL_NONE) {
+    return NANOARROW_OK;
+  }
+
   // Check buffer sizes to make sure we are not sending an ArrowArray
   // into the wild that is going to segfault
   struct ArrowArrayView array_view;
@@ -458,6 +467,11 @@ ArrowErrorCode ArrowArrayFinishBuilding(struct ArrowArray* 
array,
     return result;
   }
 
+  if (validation_level == NANOARROW_VALIDATION_LEVEL_MINIMAL) {
+    ArrowArrayViewReset(&array_view);
+    return NANOARROW_OK;
+  }
+
   result = ArrowArrayViewSetArray(&array_view, array, error);
   if (result != NANOARROW_OK) {
     ArrowArrayViewReset(&array_view);
@@ -465,10 +479,26 @@ ArrowErrorCode ArrowArrayFinishBuilding(struct 
ArrowArray* array,
   }
 
   result = ArrowArrayCheckInternalBufferSizes(array, &array_view, 0, error);
+  if (result != NANOARROW_OK) {
+    ArrowArrayViewReset(&array_view);
+    return result;
+  }
+
+  if (validation_level == NANOARROW_VALIDATION_LEVEL_DEFAULT) {
+    ArrowArrayViewReset(&array_view);
+    return NANOARROW_OK;
+  }
+
+  result = ArrowArrayViewValidateFull(&array_view, error);
   ArrowArrayViewReset(&array_view);
   return result;
 }
 
+ArrowErrorCode ArrowArrayFinishBuildingDefault(struct ArrowArray* array,
+                                               struct ArrowError* error) {
+  return ArrowArrayFinishBuilding(array, NANOARROW_VALIDATION_LEVEL_DEFAULT, 
error);
+}
+
 void ArrowArrayViewInitFromType(struct ArrowArrayView* array_view,
                                 enum ArrowType storage_type) {
   memset(array_view, 0, sizeof(struct ArrowArrayView));
diff --git a/src/nanoarrow/array_stream_test.cc 
b/src/nanoarrow/array_stream_test.cc
index efb39dc..aa2c10d 100644
--- a/src/nanoarrow/array_stream_test.cc
+++ b/src/nanoarrow/array_stream_test.cc
@@ -31,7 +31,7 @@ TEST(ArrayStreamTest, ArrayStreamTestBasic) {
   ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), 
NANOARROW_OK);
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   ArrowBasicArrayStreamSetArray(&array_stream, 0, &array);
   EXPECT_EQ(array.release, nullptr);
@@ -90,7 +90,7 @@ TEST(ArrayStreamTest, ArrayStreamTestIncomplete) {
     for (int j = 0; j < i; j++) {
       ASSERT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
     }
-    ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+    ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
     ArrowBasicArrayStreamSetArray(&array_stream, i, &array);
   }
 
@@ -114,7 +114,7 @@ TEST(ArrayStreamTest, ArrayStreamTestInvalid) {
 
   ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), 
NANOARROW_OK);
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
   ArrowBasicArrayStreamSetArray(&array_stream, 0, &array);
 
   EXPECT_EQ(ArrowBasicArrayStreamValidate(&array_stream, &error), EINVAL);
diff --git a/src/nanoarrow/array_test.cc b/src/nanoarrow/array_test.cc
index ce07da2..493541f 100644
--- a/src/nanoarrow/array_test.cc
+++ b/src/nanoarrow/array_test.cc
@@ -207,7 +207,7 @@ TEST(ArrayTest, ArrayTestBuildByBuffer) {
 
   array.length = 7;
   EXPECT_EQ(ArrowArrayShrinkToFit(&array), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
 
   EXPECT_EQ(memcmp(array.buffers[0], validity_bitmap, 1), 0);
   EXPECT_EQ(memcmp(array.buffers[1], offsets, 8 * sizeof(int32_t)), 0);
@@ -222,20 +222,102 @@ TEST(ArrayTest, ArrayTestBuildByBuffer) {
   EXPECT_EQ(ArrowArrayBuffer(&array, 2)->size_bytes, 10);
 
   array.length = 8;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected buffer 1 to size >= 36 bytes but found buffer with 32 
bytes");
 
   array.length = 7;
   int32_t* offsets_buffer = 
reinterpret_cast<int32_t*>(ArrowArrayBuffer(&array, 1)->data);
   offsets_buffer[7] = offsets_buffer[7] + 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected buffer 2 to size >= 11 bytes but found buffer with 10 
bytes");
 
   array.release(&array);
 }
 
+TEST(ArrayTest, ArrayTestExplicitValidationLevel) {
+  struct ArrowArray array;
+  struct ArrowError error;
+
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), 
NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("1234")), 
NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("5678")), 
NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, 
&error),
+            NANOARROW_OK);
+
+  int32_t* offsets =
+      const_cast<int32_t*>(reinterpret_cast<const int32_t*>(array.buffers[1]));
+
+  // Valid at validation_level < NANOARROW_VALIDATION_LEVEL_FULL
+  offsets[1] = -1;
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, 
&error),
+            NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_MINIMAL, &error),
+            NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_DEFAULT, &error),
+            NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_FULL, 
&error),
+            EINVAL);
+  EXPECT_STREQ(error.message, "[1] Expected element size >= 0 but found 
element size -1");
+  offsets[1] = 4;
+
+  // Valid at validation_level < NANOARROW_VALIDATION_LEVEL_DEFAULT
+  offsets[0] = -1;
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, 
&error),
+            NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_MINIMAL, &error),
+            NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_DEFAULT, &error),
+            EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_FULL, 
&error),
+            EINVAL);
+  EXPECT_STREQ(error.message, "Expected first offset >= 0 but found -1");
+  offsets[0] = 0;
+
+  // Valid at validation_level < NANOARROW_VALIDATION_LEVEL_MINIMAL
+  ArrowBufferReset(ArrowArrayBuffer(&array, 1));
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, 
&error),
+            NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_MINIMAL, &error),
+            EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_DEFAULT, &error),
+            EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_FULL, 
&error),
+            EINVAL);
+  EXPECT_STREQ(error.message,
+               "Expected buffer 1 to size >= 12 bytes but found buffer with 0 
bytes");
+
+  array.release(&array);
+}
+
+TEST(ArrayTest, ArrayTestValidateMinimalBufferAccess) {
+  struct ArrowArray array;
+
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), 
NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("1234")), 
NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("5678")), 
NANOARROW_OK);
+
+  // Temporarily make it so that referencing the offsets buffer will crash
+  // but make sure it has the correct size_bytes and passes minimal validation
+  uint8_t* tmp = ArrowArrayBuffer(&array, 1)->data;
+  ArrowArrayBuffer(&array, 1)->data = nullptr;
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_MINIMAL, nullptr),
+            NANOARROW_OK);
+
+  // ...and fails without crashing with the incorrect size_bytes
+  ArrowArrayBuffer(&array, 1)->size_bytes = 0;
+  EXPECT_EQ(ArrowArrayFinishBuilding(&array, 
NANOARROW_VALIDATION_LEVEL_MINIMAL, nullptr),
+            EINVAL);
+
+  // ...restore the pointer so we don't leak memory
+  ArrowArrayBuffer(&array, 1)->data = tmp;
+
+  array.release(&array);
+}
+
 TEST(ArrayTest, ArrayTestAppendToNullArray) {
   struct ArrowArray array;
   ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_NA), NANOARROW_OK);
@@ -244,7 +326,7 @@ TEST(ArrayTest, ArrayTestAppendToNullArray) {
   EXPECT_EQ(ArrowArrayAppendNull(&array, 0), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 3);
   EXPECT_EQ(array.null_count, 3);
@@ -277,7 +359,7 @@ TEST(ArrayTest, ArrayTestAppendToInt64Array) {
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 3), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 
std::numeric_limits<uint64_t>::max()), EINVAL);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 5);
   EXPECT_EQ(array.null_count, 2);
@@ -311,7 +393,7 @@ TEST(ArrayTest, ArrayTestAppendToInt32Array) {
   EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), 
EINVAL);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 
std::numeric_limits<uint64_t>::max()), EINVAL);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 1);
   EXPECT_EQ(array.null_count, 0);
@@ -337,7 +419,7 @@ TEST(ArrayTest, ArrayTestAppendToInt16Array) {
   EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), 
EINVAL);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 
std::numeric_limits<uint64_t>::max()), EINVAL);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 1);
   EXPECT_EQ(array.null_count, 0);
@@ -363,7 +445,7 @@ TEST(ArrayTest, ArrayTestAppendToInt8Array) {
   EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), 
EINVAL);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 
std::numeric_limits<uint64_t>::max()), EINVAL);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 1);
   EXPECT_EQ(array.null_count, 0);
@@ -395,7 +477,7 @@ TEST(ArrayTest, ArrayTestAppendToStringArray) {
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("56789")), 
NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 5);
   EXPECT_EQ(array.null_count, 2);
@@ -428,7 +510,7 @@ TEST(ArrayTest, ArrayTestAppendEmptyToString) {
   ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), 
NANOARROW_OK);
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendString(&array, ArrowCharView("")), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
   EXPECT_NE(array.buffers[2], nullptr);
   array.release(&array);
 }
@@ -441,7 +523,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt64Array) {
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 4);
   EXPECT_EQ(array.null_count, 2);
@@ -476,7 +558,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt32Array) {
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 
std::numeric_limits<uint64_t>::max()), EINVAL);
   EXPECT_EQ(ArrowArrayAppendInt(&array, -1), EINVAL);
 
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 2);
   EXPECT_EQ(array.null_count, 0);
@@ -507,7 +589,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt16Array) {
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 
std::numeric_limits<uint64_t>::max()), EINVAL);
   EXPECT_EQ(ArrowArrayAppendInt(&array, -1), EINVAL);
 
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 2);
   EXPECT_EQ(array.null_count, 0);
@@ -538,7 +620,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt8Array) {
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 
std::numeric_limits<uint64_t>::max()), EINVAL);
   EXPECT_EQ(ArrowArrayAppendInt(&array, -1), EINVAL);
 
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 2);
   EXPECT_EQ(array.null_count, 0);
@@ -574,7 +656,7 @@ TEST(ArrayTest, ArrayTestAppendToDoubleArray) {
   EXPECT_EQ(ArrowArrayAppendDouble(&array, -INFINITY), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendDouble(&array, -1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendDouble(&array, 0), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 11);
   EXPECT_EQ(array.null_count, 2);
@@ -631,7 +713,7 @@ TEST(ArrayTest, ArrayTestAppendToFloatArray) {
   EXPECT_EQ(ArrowArrayAppendDouble(&array, -INFINITY), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendDouble(&array, -1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendDouble(&array, 0), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 11);
   EXPECT_EQ(array.null_count, 2);
@@ -679,7 +761,7 @@ TEST(ArrayTest, ArrayTestAppendToBoolArray) {
   EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 0), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 4);
   EXPECT_EQ(array.null_count, 2);
@@ -717,7 +799,7 @@ TEST(ArrayTest, ArrayTestAppendToLargeStringArray) {
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("56789")), 
NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 5);
   EXPECT_EQ(array.null_count, 2);
@@ -764,7 +846,7 @@ TEST(ArrayTest, ArrayTestAppendToFixedSizeBinaryArray) {
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendBytes(&array, {"67890", 5}), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(array.length, 5);
   EXPECT_EQ(array.null_count, 2);
@@ -818,20 +900,20 @@ TEST(ArrayTest, ArrayTestAppendToListArray) {
 
   // Make sure number of children is checked at finish
   array.n_children = 0;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected 1 child of list array but found 0 child arrays");
   array.n_children = 1;
 
   // Make sure final child size is checked at finish
   array.children[0]->length = array.children[0]->length - 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(
       ArrowErrorMessage(&error),
       "Expected child of list array with length >= 3 but found array with 
length 2");
 
   array.children[0]->length = array.children[0]->length + 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
 
   auto arrow_array = ImportArray(&array, &schema);
   ARROW_EXPECT_OK(arrow_array);
@@ -879,20 +961,20 @@ TEST(ArrayTest, ArrayTestAppendToLargeListArray) {
 
   // Make sure number of children is checked at finish
   array.n_children = 0;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected 1 child of large list array but found 0 child 
arrays");
   array.n_children = 1;
 
   // Make sure final child size is checked at finish
   array.children[0]->length = array.children[0]->length - 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected child of large list array with length >= 3 but found 
array with "
                "length 2");
 
   array.children[0]->length = array.children[0]->length + 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
 
   auto arrow_array = ImportArray(&array, &schema);
   ARROW_EXPECT_OK(arrow_array);
@@ -944,20 +1026,20 @@ TEST(ArrayTest, ArrayTestAppendToMapArray) {
 
   // Make sure number of children is checked at finish
   array.n_children = 0;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected 1 child of map array but found 0 child arrays");
   array.n_children = 1;
 
   // Make sure final child size is checked at finish
   array.children[0]->length = array.children[0]->length - 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(
       ArrowErrorMessage(&error),
       "Expected child of map array with length >= 1 but found array with 
length 0");
 
   array.children[0]->length = array.children[0]->length + 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
 
   auto maybe_arrow_array = ImportArray(&array, &schema);
   ARROW_EXPECT_OK(maybe_arrow_array);
@@ -1011,20 +1093,20 @@ TEST(ArrayTest, ArrayTestAppendToFixedSizeListArray) {
 
   // Make sure number of children is checked at finish
   array.n_children = 0;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected 1 child of fixed-size array but found 0 child 
arrays");
   array.n_children = 1;
 
   // Make sure final child size is checked at finish
   array.children[0]->length = array.children[0]->length - 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, &error), EINVAL);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected child of fixed-size list array with length >= 8 but 
found array "
                "with length 7");
 
   array.children[0]->length = array.children[0]->length + 1;
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   auto arrow_array = ImportArray(&array, &schema);
   ARROW_EXPECT_OK(arrow_array);
@@ -1075,7 +1157,7 @@ TEST(ArrayTest, ArrayTestAppendToStructArray) {
 
   ASSERT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
 
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   auto arrow_array = ImportArray(&array, &schema);
   ARROW_EXPECT_OK(arrow_array);
@@ -1148,7 +1230,7 @@ TEST(ArrayTest, ArrayTestAppendToDenseUnionArray) {
   EXPECT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
 
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   auto arrow_array = ImportArray(&array, &schema);
   ARROW_EXPECT_OK(arrow_array);
@@ -1193,7 +1275,7 @@ TEST(ArrayTest, ArrayTestAppendToSparseUnionArray) {
             NANOARROW_OK);
   EXPECT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   auto arrow_array = ImportArray(&array, &schema);
   ARROW_EXPECT_OK(arrow_array);
@@ -1264,7 +1346,7 @@ TEST(ArrayTest, ArrayViewTestBasic) {
   ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 13), 
NANOARROW_OK);
   array.length = 3;
   array.null_count = 0;
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
@@ -1277,7 +1359,7 @@ TEST(ArrayTest, ArrayViewTestBasic) {
   // Build with validity buffer
   ASSERT_EQ(ArrowBitmapAppend(ArrowArrayValidityBitmap(&array), 1, 3), 
NANOARROW_OK);
   array.null_count = -1;
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
@@ -1362,7 +1444,7 @@ TEST(ArrayTest, ArrayViewTestString) {
   ASSERT_EQ(ArrowBufferReserve(ArrowArrayBuffer(&array, 2), 4), NANOARROW_OK);
   ArrowBufferAppendUnsafe(ArrowArrayBuffer(&array, 2), "abcd", 4);
   array.length = 1;
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
@@ -1430,7 +1512,7 @@ TEST(ArrayTest, ArrayViewTestLargeString) {
   ASSERT_EQ(ArrowBufferReserve(ArrowArrayBuffer(&array, 2), 4), NANOARROW_OK);
   ArrowBufferAppendUnsafe(ArrowArrayBuffer(&array, 2), "abcd", 4);
   array.length = 1;
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
@@ -1516,7 +1598,7 @@ TEST(ArrayTest, ArrayViewTestList) {
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 1234), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), 
NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, nullptr), NANOARROW_OK);
@@ -1569,7 +1651,7 @@ TEST(ArrayTest, ArrayViewTestLargeList) {
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 1234), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), 
NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, nullptr), NANOARROW_OK);
@@ -1646,7 +1728,7 @@ TEST(ArrayTest, ArrayViewTestStructArray) {
   ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(array.children[0], 1), 
123),
             NANOARROW_OK);
   array.children[0]->length = 1;
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
@@ -1689,7 +1771,7 @@ TEST(ArrayTest, ArrayViewTestFixedSizeListArray) {
   ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(array.children[0], 1), 
789),
             NANOARROW_OK);
   array.children[0]->length = 3;
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, &error), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
@@ -1720,7 +1802,7 @@ TEST(ArrayTest, ArrayViewTestUnionChildIndices) {
   ASSERT_EQ(ArrowArrayAppendString(array.children[1], ArrowCharView("one 
twenty four")),
             NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   // The ArrayView for a union could in theroy be created without a schema,
   // in which case the type_ids are assumed to equal child indices
@@ -1822,7 +1904,7 @@ TEST(ArrayTest, ArrayViewTestDenseUnionGet) {
             NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   // Initialize the array view
   ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), 
NANOARROW_OK);
@@ -1867,7 +1949,7 @@ TEST(ArrayTest, ArrayViewTestSparseUnionGet) {
             NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
 
   // Initialize the array view
   ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), 
NANOARROW_OK);
diff --git a/src/nanoarrow/nanoarrow.h b/src/nanoarrow/nanoarrow.h
index 558d3d1..9b67c4f 100644
--- a/src/nanoarrow/nanoarrow.h
+++ b/src/nanoarrow/nanoarrow.h
@@ -102,6 +102,8 @@
 #define ArrowArrayReserve NANOARROW_SYMBOL(NANOARROW_NAMESPACE, 
ArrowArrayReserve)
 #define ArrowArrayFinishBuilding \
   NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayFinishBuilding)
+#define ArrowArrayFinishBuildingDefault \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayFinishBuildingDefault)
 #define ArrowArrayViewInitFromType \
   NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayViewInitFromType)
 #define ArrowArrayViewInitFromSchema \
@@ -704,7 +706,10 @@ static inline void ArrowBitmapReset(struct ArrowBitmap* 
bitmap);
 
 /// \defgroup nanoarrow-array Creating arrays
 ///
-/// These functions allocate, copy, and destroy ArrowArray structures
+/// These functions allocate, copy, and destroy ArrowArray structures.
+/// Once an ArrowArray has been initialized via ArrowArrayInitFromType()
+/// or ArrowArrayInitFromSchema(), the caller is responsible for releasing
+/// it using the embedded release callback.
 ///
 /// @{
 
@@ -852,10 +857,21 @@ static inline ArrowErrorCode ArrowArrayShrinkToFit(struct 
ArrowArray* array);
 /// \brief Finish building an ArrowArray
 ///
 /// Flushes any pointers from internal buffers that may have been reallocated
-/// into the array->buffers array and checks the actual size of the buffers
+/// into array->buffers and checks the actual size of the buffers
 /// against the expected size based on the final length.
 /// array must have been allocated using ArrowArrayInitFromType()
+ArrowErrorCode ArrowArrayFinishBuildingDefault(struct ArrowArray* array,
+                                               struct ArrowError* error);
+
+/// \brief Finish building an ArrowArray with explicit validation
+///
+/// Finish building with an explicit validation level. This could perform less 
validation
+/// (i.e. NANOARROW_VALIDATION_LEVEL_NONE or 
NANOARROW_VALIDATION_LEVEL_MINIMAL) if CPU
+/// buffer data access is not possible or more validation (i.e.,
+/// NANOARROW_VALIDATION_LEVEL_FULL) if buffer content was obtained from an 
untrusted or
+/// corruptable source.
 ArrowErrorCode ArrowArrayFinishBuilding(struct ArrowArray* array,
+                                        enum ArrowValidationLevel 
validation_level,
                                         struct ArrowError* error);
 
 /// @}
diff --git a/src/nanoarrow/nanoarrow_hpp_test.cc 
b/src/nanoarrow/nanoarrow_hpp_test.cc
index b3ed58a..bd5393a 100644
--- a/src/nanoarrow/nanoarrow_hpp_test.cc
+++ b/src/nanoarrow/nanoarrow_hpp_test.cc
@@ -26,7 +26,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayTest) {
   ArrowArrayInitFromType(array.get(), NANOARROW_TYPE_INT32);
   ASSERT_EQ(ArrowArrayStartAppending(array.get()), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendInt(array.get(), 123), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayFinishBuilding(array.get(), nullptr), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(array.get(), nullptr), 
NANOARROW_OK);
 
   EXPECT_NE(array->release, nullptr);
   EXPECT_EQ(array->length, 1);
@@ -191,7 +191,7 @@ TEST(NanoarrowHppTest, NanoarrowHppVectorArrayStreamTest) {
   EXPECT_EQ(ArrowArrayInitFromType(array_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(array_in.get()), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(array_in.get(), 1234), NANOARROW_OK);
-  EXPECT_EQ(ArrowArrayFinishBuilding(array_in.get(), nullptr), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuildingDefault(array_in.get(), nullptr), 
NANOARROW_OK);
 
   nanoarrow::UniqueSchema schema_in;
   EXPECT_EQ(ArrowSchemaInitFromType(schema_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
diff --git a/src/nanoarrow/nanoarrow_types.h b/src/nanoarrow/nanoarrow_types.h
index b9af6bb..c8eede8 100644
--- a/src/nanoarrow/nanoarrow_types.h
+++ b/src/nanoarrow/nanoarrow_types.h
@@ -319,6 +319,25 @@ enum ArrowTimeUnit {
   NANOARROW_TIME_UNIT_NANO = 3
 };
 
+/// \brief Validation level enumerator
+/// \ingroup nanoarrow-array
+enum ArrowValidationLevel {
+  /// \brief Do not validate buffer sizes or content.
+  NANOARROW_VALIDATION_LEVEL_NONE = 0,
+
+  /// \brief Validate buffer sizes that depend on array length but do not 
validate buffer
+  /// sizes that depend on buffer data access.
+  NANOARROW_VALIDATION_LEVEL_MINIMAL = 1,
+
+  /// \brief Validate all buffer sizes, including those that require buffer 
data access,
+  /// but do not perform any checks that are O(1) along the length of the 
buffers.
+  NANOARROW_VALIDATION_LEVEL_DEFAULT = 2,
+
+  /// \brief Validate all buffer sizes and all buffer content. This is useful 
in the
+  /// context of untrusted input or input that may have been corrupted in 
transit.
+  NANOARROW_VALIDATION_LEVEL_FULL = 3
+};
+
 /// \brief Get a string value of an enum ArrowTimeUnit value
 /// \ingroup nanoarrow-utils
 ///


Reply via email to