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 f7be6f32 fix(arrow/flight/session): clone option values (#1044)
f7be6f32 is described below
commit f7be6f32f846cd8bcb7d5222ad804905163fdf86
Author: Minh Vu <[email protected]>
AuthorDate: Wed Aug 5 19:39:15 2026 +0200
fix(arrow/flight/session): clone option values (#1044)
## What changed
Clone mutable Flight session option protobufs when storing and
retrieving individual option values.
## Why
The stateful session implementation previously stored caller-owned
pointers and returned its internal pointers after releasing the mutex.
Callers could therefore mutate session state outside synchronization,
despite the implementation's goroutine-safety contract.
The regression test covers both aliasing directions: modifying the input
after `SetSessionOption` and modifying the value returned by
`GetSessionOption`.
## Validation
`go test ./arrow/flight/session`
`go test -race ./arrow/flight/session`
---
arrow/flight/session/session.go | 4 ++--
arrow/flight/session/session_test.go | 40 ++++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/arrow/flight/session/session.go b/arrow/flight/session/session.go
index 202de38b..6c2278ac 100644
--- a/arrow/flight/session/session.go
+++ b/arrow/flight/session/session.go
@@ -108,7 +108,7 @@ func (session *serverSession) GetSessionOption(name string)
*flight.SessionOptio
return nil
}
- return value
+ return proto.Clone(value).(*flight.SessionOptionValue)
}
func (session *serverSession) GetSessionOptions()
map[string]*flight.SessionOptionValue {
@@ -131,7 +131,7 @@ func (session *serverSession) SetSessionOption(name string,
value *flight.Sessio
session.mu.Lock()
defer session.mu.Unlock()
- session.options[name] = value
+ session.options[name] = proto.Clone(value).(*flight.SessionOptionValue)
}
func (session *serverSession) EraseSessionOption(name string) {
diff --git a/arrow/flight/session/session_test.go
b/arrow/flight/session/session_test.go
new file mode 100644
index 00000000..c280eac9
--- /dev/null
+++ b/arrow/flight/session/session_test.go
@@ -0,0 +1,40 @@
+// 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 session
+
+import (
+ "testing"
+
+ "github.com/apache/arrow-go/v18/arrow/flight"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestServerSessionClonesOptionValues(t *testing.T) {
+ session := serverSession{options:
make(map[string]*flight.SessionOptionValue)}
+ values, err := flight.NewSessionOptionValues(map[string]any{"key":
[]string{"original"}})
+ require.NoError(t, err)
+ value := values["key"]
+
+ session.SetSessionOption("key", value)
+ value.GetStringListValue().Values[0] = "modified input"
+ assert.Equal(t, []string{"original"},
session.GetSessionOption("key").GetStringListValue().GetValues())
+
+ got := session.GetSessionOption("key")
+ got.GetStringListValue().Values[0] = "modified output"
+ assert.Equal(t, []string{"original"},
session.GetSessionOption("key").GetStringListValue().GetValues())
+}