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 0ad2d1db fix(arrow): avoid retains on invalid chunk construction
(#1078)
0ad2d1db is described below
commit 0ad2d1db696dbb1fef7b1c477c2db5d5e12bb2d7
Author: Minh Vu <[email protected]>
AuthorDate: Wed Aug 5 20:15:30 2026 +0200
fix(arrow): avoid retains on invalid chunk construction (#1078)
### Rationale for this change
NewChunked validated and retained inputs in the same loop. If an early
chunk matched the requested datatype but a later chunk did not, the
function panicked after retaining the earlier chunk. Callers that
recovered and released their own references could not free its buffers.
### What changes are included in this PR?
Validate every non-nil chunk datatype before retaining any input.
Invalid construction now leaves all caller-owned reference counts
unchanged. Successful construction, nil-chunk handling, and the existing
panic value are unchanged.
### Are these changes tested?
Yes. The existing invalid-chunk test now places a valid chunk before the
mismatched chunk. Its checked allocator therefore verifies rollback in
addition to the existing exact ErrInvalid assertion.
- go test ./arrow/array
- go test -race ./arrow/array -run '^TestChunkedInvalid$' -count=1
### Are there any user-facing changes?
No API changes. Recovering from invalid chunk construction no longer
leaves earlier inputs retained.
---
arrow/array/table_test.go | 4 +++-
arrow/table.go | 9 ++++++---
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/arrow/array/table_test.go b/arrow/array/table_test.go
index 08fea1a8..4720f606 100644
--- a/arrow/array/table_test.go
+++ b/arrow/array/table_test.go
@@ -203,8 +203,10 @@ func TestChunkedInvalid(t *testing.T) {
}
}()
+ // Keep a valid chunk before the mismatch so failed construction must
not
+ // leave an extra reference to it.
c1 := arrow.NewChunked(arrow.PrimitiveTypes.Int32, []arrow.Array{
- f1, f2,
+ f2, f1,
})
defer c1.Release()
}
diff --git a/arrow/table.go b/arrow/table.go
index bdbf85bf..4f873350 100644
--- a/arrow/table.go
+++ b/arrow/table.go
@@ -146,6 +146,12 @@ type Chunked struct {
//
// NewChunked panics if the chunks do not have the same data type.
func NewChunked(dtype DataType, chunks []Array) *Chunked {
+ for _, chunk := range chunks {
+ if chunk != nil && !TypeEqual(chunk.DataType(), dtype) {
+ panic(fmt.Errorf("%w: arrow/array: mismatch data type
%s vs %s", ErrInvalid, chunk.DataType().String(), dtype.String()))
+ }
+ }
+
arr := &Chunked{
chunks: make([]Array, 0, len(chunks)),
dtype: dtype,
@@ -157,9 +163,6 @@ func NewChunked(dtype DataType, chunks []Array) *Chunked {
continue
}
- if !TypeEqual(chunk.DataType(), dtype) {
- panic(fmt.Errorf("%w: arrow/array: mismatch data type
%s vs %s", ErrInvalid, chunk.DataType().String(), dtype.String()))
- }
chunk.Retain()
arr.chunks = append(arr.chunks, chunk)
arr.length += chunk.Len()