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

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 666f8dc2 fix(arrow/array): validate union child upper bound (#1043)
666f8dc2 is described below

commit 666f8dc2ea470d69fc294ba1f850d04050fb5047
Author: Minh Vu <[email protected]>
AuthorDate: Tue Jul 28 17:08:22 2026 +0200

    fix(arrow/array): validate union child upper bound (#1043)
    
    ## What changed
    
    Reject a union child index equal to the number of children.
    
    ## Why
    
    The previous bounds check allowed `idx == len(children)` through,
    causing a generic runtime index panic instead of the intended Arrow
    validation panic.
    
    The regression test covers both the negative and upper bounds for dense
    and sparse union builders.
    
    ## Validation
    
    `go test ./arrow/array`
---
 arrow/array/union.go      |  2 +-
 arrow/array/union_test.go | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/arrow/array/union.go b/arrow/array/union.go
index 2b6c55f1..6329ea74 100644
--- a/arrow/array/union.go
+++ b/arrow/array/union.go
@@ -801,7 +801,7 @@ func (b *unionBuilder) NumChildren() int {
 }
 
 func (b *unionBuilder) Child(idx int) Builder {
-       if idx < 0 || idx > len(b.children) {
+       if idx < 0 || idx >= len(b.children) {
                panic("arrow/array: invalid child index for union builder")
        }
        return b.children[idx]
diff --git a/arrow/array/union_test.go b/arrow/array/union_test.go
index 24c85552..fd234aad 100644
--- a/arrow/array/union_test.go
+++ b/arrow/array/union_test.go
@@ -42,6 +42,41 @@ func int32ArrFromSlice(offsets ...int32) arrow.Array {
        return array.MakeFromData(data)
 }
 
+func TestUnionBuilderChildBounds(t *testing.T) {
+       fields := []arrow.Field{{Name: "value", Type: 
arrow.PrimitiveTypes.Int32}}
+       codes := []arrow.UnionTypeCode{0}
+       tests := []struct {
+               name string
+               new  func() array.UnionBuilder
+       }{
+               {
+                       name: "dense",
+                       new: func() array.UnionBuilder {
+                               return 
array.NewDenseUnionBuilder(memory.DefaultAllocator, arrow.DenseUnionOf(fields, 
codes))
+                       },
+               },
+               {
+                       name: "sparse",
+                       new: func() array.UnionBuilder {
+                               return 
array.NewSparseUnionBuilder(memory.DefaultAllocator, 
arrow.SparseUnionOf(fields, codes))
+                       },
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       builder := tt.new()
+                       defer builder.Release()
+
+                       for _, index := range []int{-1, len(fields)} {
+                               assert.PanicsWithValue(t, "arrow/array: invalid 
child index for union builder", func() {
+                                       builder.Child(index)
+                               })
+                       }
+               })
+       }
+}
+
 func TestUnionSliceEquals(t *testing.T) {
        unionFields := []arrow.Field{
                {Name: "u0", Type: arrow.PrimitiveTypes.Int32, Nullable: true},

Reply via email to