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 07836b1d fix(parquet): guard byte-stream-split encoder release against 
never-flushed buffer (#1273)
07836b1d is described below

commit 07836b1df187a2b564b3be624dc96ff8fb30706b
Author: Tom Frank <[email protected]>
AuthorDate: Wed Sep 2 19:48:49 2026 +0300

    fix(parquet): guard byte-stream-split encoder release against never-flushed 
buffer (#1273)
    
    ### Rationale for this change
    
    `byteStreamSplitEncoder.Release` unconditionally passes
    `enc.flushBuffer` to `releaseBufferToPool`, which dereferences it. The
    flush buffer is allocated lazily on the first `FlushValues`, so
    releasing an encoder that never flushed — which `columnWriter.Close`
    does for a column chunk that received no values — dereferences nil and
    crashes the process with a SIGSEGV.
    `ByteStreamSplitFixedLenByteArrayEncoder.Release` has the same defect.
    
    ### What changes are included in this PR?
    
    A nil guard at the top of `releaseBufferToPool`, covering both encoders,
    plus a regression test that releases a never-flushed BYTE_STREAM_SPLIT
    encoder for all five physical types (INT32, INT64, FLOAT, DOUBLE,
    FIXED_LEN_BYTE_ARRAY).
    
    ### Are these changes tested?
    
    Yes. The new test panics on every subtest without the fix and passes
    with it; the existing `parquet/internal/encoding` and `parquet/file`
    suites pass.
    
    ### Are there any user-facing changes?
    
    No API changes. Writing a parquet file with a BYTE_STREAM_SPLIT column
    no longer panics when a column chunk ends up empty (e.g. an empty
    trailing row group).
    
    Co-authored-by: Claude Fable 5 <[email protected]>
---
 parquet/internal/encoding/byte_stream_split.go     |  6 +++
 .../encoding/byte_stream_split_release_test.go     | 52 ++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/parquet/internal/encoding/byte_stream_split.go 
b/parquet/internal/encoding/byte_stream_split.go
index 970e0f88..d5820093 100644
--- a/parquet/internal/encoding/byte_stream_split.go
+++ b/parquet/internal/encoding/byte_stream_split.go
@@ -94,6 +94,12 @@ var (
 )
 
 func releaseBufferToPool(pooled *PooledBufferWriter) {
+       // the byte-stream-split encoders allocate their flush buffer lazily on 
the first
+       // FlushValues, so releasing an encoder that never flushed (e.g. a 
column chunk that
+       // received no values) passes nil here
+       if pooled == nil {
+               return
+       }
        buf := pooled.buf
        memory.Set(buf.Buf(), 0)
        buf.ResizeNoShrink(0)
diff --git a/parquet/internal/encoding/byte_stream_split_release_test.go 
b/parquet/internal/encoding/byte_stream_split_release_test.go
new file mode 100644
index 00000000..0b678787
--- /dev/null
+++ b/parquet/internal/encoding/byte_stream_split_release_test.go
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package encoding
+
+import (
+       "testing"
+
+       "github.com/apache/arrow-go/v18/arrow/memory"
+       "github.com/apache/arrow-go/v18/parquet"
+       "github.com/apache/arrow-go/v18/parquet/schema"
+       "github.com/stretchr/testify/assert"
+)
+
+// The byte-stream-split encoders allocate their flush buffer lazily on the 
first
+// FlushValues, so an encoder released without ever flushing (as 
columnWriter.Close
+// does for a column chunk that received no values) must not dereference the 
nil buffer.
+func TestByteStreamSplitReleaseWithoutFlush(t *testing.T) {
+       tests := []struct {
+               name    string
+               typ     parquet.Type
+               typeLen int32
+       }{
+               {"int32", parquet.Types.Int32, -1},
+               {"int64", parquet.Types.Int64, -1},
+               {"float32", parquet.Types.Float, -1},
+               {"float64", parquet.Types.Double, -1},
+               {"fixed_len_byte_array", parquet.Types.FixedLenByteArray, 4},
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       descr := 
schema.NewColumn(schema.MustPrimitive(schema.NewPrimitiveNode(
+                               "col", parquet.Repetitions.Required, tt.typ, 
-1, tt.typeLen)), 0, 0)
+                       enc := NewEncoder(tt.typ, 
parquet.Encodings.ByteStreamSplit, false, descr, memory.DefaultAllocator)
+                       assert.NotPanics(t, enc.Release)
+               })
+       }
+}

Reply via email to