This is an automated email from the ASF dual-hosted git repository.

curth 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 8fd3ce9e64 GH-40898: [C#] Do not import length-zero buffers from C 
Data Interface Arrays (#41054)
8fd3ce9e64 is described below

commit 8fd3ce9e64565935b17c87bd00037d8e96528cce
Author: Dewey Dunnington <[email protected]>
AuthorDate: Sun Apr 7 12:23:43 2024 -0300

    GH-40898: [C#] Do not import length-zero buffers from C Data Interface 
Arrays (#41054)
    
    
    ### Rationale for this change
    
    When implementing integration tests for nanoarrow, it was observed that C# 
never released arrays where `array->buffers[i]` was `NULL` (including any 
buffers of any recursive child arrays). This is allowed ( 
https://arrow.apache.org/docs/format/CDataInterface.html#c.ArrowArray.buffers 
); however, every other implementation appears to allocate even for length zero 
buffers (including nanoarrow after 
https://github.com/apache/arrow-nanoarrow/pull/399 ).
    
    ### What changes are included in this PR?
    
    `AddMemory()` is replaced with `ArrowBuffer.Empty` if the length of the 
imported buffer would have been 0 bytes. For other buffers (or anywhere I saw 
dereferencing a buffer pointer), I added a `Debug.Assert` just to be sure.
    
    ### Are these changes tested?
    
    I'm not sure what the best way to test them is! They won't be tested in the 
nanoarrow integration tests since at the point that they run, nanoarrow will no 
longer export arrays that would trigger this.
    
    ### Are there any user-facing changes?
    
    No
    * GitHub Issue: #40898
    
    Authored-by: Dewey Dunnington <[email protected]>
    Signed-off-by: Curt Hagenlocher <[email protected]>
---
 csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs | 41 ++++++++++++++++--------
 1 file changed, 28 insertions(+), 13 deletions(-)

diff --git a/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs 
b/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs
index fbb2be661f..abe02dcbb5 100644
--- a/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs
+++ b/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs
@@ -17,6 +17,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Runtime.InteropServices;
 using Apache.Arrow.Memory;
 using Apache.Arrow.Types;
@@ -36,7 +37,7 @@ namespace Apache.Arrow.C
         /// Typically, you will allocate an uninitialized CArrowArray pointer,
         /// pass that to external function, and then use this method to import
         /// the result.
-        /// 
+        ///
         /// <code>
         /// CArrowArray* importedPtr = CArrowArray.Create();
         /// foreign_export_function(importedPtr);
@@ -71,7 +72,7 @@ namespace Apache.Arrow.C
         /// Typically, you will allocate an uninitialized CArrowArray pointer,
         /// pass that to external function, and then use this method to import
         /// the result.
-        /// 
+        ///
         /// <code>
         /// CArrowArray* importedPtr = CArrowArray.Create();
         /// foreign_export_function(importedPtr);
@@ -256,6 +257,19 @@ namespace Apache.Arrow.C
                 return (cArray->buffers[0] == null) ? ArrowBuffer.Empty : new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[0], 0, validityLength));
             }
 
+            private ArrowBuffer ImportCArrayBuffer(CArrowArray* cArray, int i, 
int lengthBytes)
+            {
+                if (lengthBytes > 0)
+                {
+                    Debug.Assert(cArray->buffers[i] != null);
+                    return new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[i], 0, lengthBytes));
+                }
+                else
+                {
+                    return ArrowBuffer.Empty;
+                }
+            }
+
             private ArrowBuffer[] ImportByteArrayBuffers(CArrowArray* cArray)
             {
                 if (cArray->n_buffers != 3)
@@ -266,12 +280,13 @@ namespace Apache.Arrow.C
                 int length = checked((int)cArray->length);
                 int offsetsLength = (length + 1) * 4;
                 int* offsets = (int*)cArray->buffers[1];
+                Debug.Assert(offsets != null);
                 int valuesLength = offsets[length];
 
                 ArrowBuffer[] buffers = new ArrowBuffer[3];
                 buffers[0] = ImportValidityBuffer(cArray);
-                buffers[1] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[1], 0, offsetsLength));
-                buffers[2] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[2], 0, valuesLength));
+                buffers[1] = ImportCArrayBuffer(cArray, 1, offsetsLength);
+                buffers[2] = ImportCArrayBuffer(cArray, 2, valuesLength);
 
                 return buffers;
             }
@@ -289,10 +304,10 @@ namespace Apache.Arrow.C
                 long* bufferLengths = (long*)cArray->buffers[cArray->n_buffers 
- 1];
                 ArrowBuffer[] buffers = new ArrowBuffer[cArray->n_buffers - 1];
                 buffers[0] = ImportValidityBuffer(cArray);
-                buffers[1] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[1], 0, viewsLength));
+                buffers[1] = ImportCArrayBuffer(cArray, 1, viewsLength);
                 for (int i = 2; i < buffers.Length; i++)
                 {
-                    buffers[i] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[i], 0, 
checked((int)bufferLengths[i - 2])));
+                    buffers[i] = ImportCArrayBuffer(cArray, i, 
checked((int)bufferLengths[i - 2]));
                 }
 
                 return buffers;
@@ -310,7 +325,7 @@ namespace Apache.Arrow.C
 
                 ArrowBuffer[] buffers = new ArrowBuffer[2];
                 buffers[0] = ImportValidityBuffer(cArray);
-                buffers[1] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[1], 0, offsetsLength));
+                buffers[1] = ImportCArrayBuffer(cArray, 1, offsetsLength);
 
                 return buffers;
             }
@@ -327,8 +342,8 @@ namespace Apache.Arrow.C
 
                 ArrowBuffer[] buffers = new ArrowBuffer[3];
                 buffers[0] = ImportValidityBuffer(cArray);
-                buffers[1] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[1], 0, offsetsLength));
-                buffers[2] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[2], 0, offsetsLength));
+                buffers[1] = ImportCArrayBuffer(cArray, 1, offsetsLength);
+                buffers[2] = ImportCArrayBuffer(cArray, 2, offsetsLength);
 
                 return buffers;
             }
@@ -356,8 +371,8 @@ namespace Apache.Arrow.C
                 int offsetsLength = length * 4;
 
                 ArrowBuffer[] buffers = new ArrowBuffer[2];
-                buffers[0] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[0], 0, length));
-                buffers[1] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[1], 0, offsetsLength));
+                buffers[0] = ImportCArrayBuffer(cArray, 0, length);
+                buffers[1] = ImportCArrayBuffer(cArray, 1, offsetsLength);
 
                 return buffers;
             }
@@ -370,7 +385,7 @@ namespace Apache.Arrow.C
                 }
 
                 ArrowBuffer[] buffers = new ArrowBuffer[1];
-                buffers[0] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[0], 0, 
checked((int)cArray->length)));
+                buffers[0] = ImportCArrayBuffer(cArray, 0, 
checked((int)cArray->length));
 
                 return buffers;
             }
@@ -392,7 +407,7 @@ namespace Apache.Arrow.C
 
                 ArrowBuffer[] buffers = new ArrowBuffer[2];
                 buffers[0] = ImportValidityBuffer(cArray);
-                buffers[1] = new 
ArrowBuffer(AddMemory((IntPtr)cArray->buffers[1], 0, valuesLength));
+                buffers[1] = ImportCArrayBuffer(cArray, 1, valuesLength);
 
                 return buffers;
             }

Reply via email to