Skip to content

Commit 0b2f755

Browse files
Ragnaroekmibo-fdcmatthewdale
authored
GODRIVER-3307 clone returned byte slice in MarshalValue (#1913)
Co-authored-by: Michael Bohn <[email protected]> Co-authored-by: Matt Dale <[email protected]>
1 parent 12b08ac commit 0b2f755

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

bson/marshal.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ func MarshalValue(val interface{}) (Type, []byte, error) {
133133
return 0, nil, err
134134
}
135135
typ := sw.Next(2)
136-
return Type(typ[0]), sw.Bytes(), nil
136+
clone := append([]byte{}, sw.Bytes()...) // Don't hand out a shared reference to byte buffer bytes
137+
// and fully copy the data. The byte buffer is (potentially) reused
138+
// and handing out only a reference to the bytes may lead to race-conditions with the buffer.
139+
return Type(typ[0]), clone, nil
137140
}
138141

139142
// MarshalExtJSON returns the extended JSON encoding of val.

bson/marshal_value_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"testing"
1212

1313
"go.mongodb.org/mongo-driver/v2/internal/assert"
14+
"go.mongodb.org/mongo-driver/v2/internal/require"
1415
)
1516

1617
func TestMarshalValue(t *testing.T) {
@@ -33,6 +34,25 @@ func TestMarshalValue(t *testing.T) {
3334
})
3435
}
3536
})
37+
38+
t.Run("returns distinct address ranges", func(t *testing.T) {
39+
// Call MarshalValue in a loop with the same large value (make sure to
40+
// trigger the buffer pooling, which currently doesn't happen for very
41+
// small values). Compare the previous and current BSON byte slices and
42+
// make sure they always have distinct memory ranges.
43+
//
44+
// Don't run this test in parallel to maximize the chance that we get
45+
// the same pooled buffer for most/all calls.
46+
largeVal := strings.Repeat("1234567890", 100_000)
47+
var prev []byte
48+
for i := 0; i < 20; i++ {
49+
_, b, err := MarshalValue(largeVal)
50+
require.NoError(t, err)
51+
52+
assert.DifferentAddressRanges(t, b, prev)
53+
prev = b
54+
}
55+
})
3656
}
3757

3858
func compareMarshalValueResults(t *testing.T, tc marshalValueTestCase, gotType Type, gotBytes []byte) {

0 commit comments

Comments
 (0)