Skip to content

Commit fcfea70

Browse files
authored
GODRIVER-3809 Fix *streamingByteSrc.readSlice(). (#2326)
1 parent 889822d commit fcfea70

File tree

3 files changed

+57
-8
lines changed

3 files changed

+57
-8
lines changed

bson/buffered_byte_src.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (b *bufferedByteSrc) discard(n int) (int, error) {
6868
return n, nil
6969
}
7070

71-
// readSlice scans buf[offset:] for the first occurrence of delim, returns
71+
// readSlice reads buf[offset:] for the first occurrence of delim, returning
7272
// buf[offset:idx+1], and advances offset past it; errors if delim not found.
7373
func (b *bufferedByteSrc) readSlice(delim byte) ([]byte, error) {
7474
// Ensure we don't read past the end of the buffer.

bson/streaming_byte_src.go

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,43 @@ func (s *streamingByteSrc) discard(n int) (int, error) {
5656
return m, err
5757
}
5858

59-
// readSlice scans buf[offset:] for the first occurrence of delim, returns
60-
// buf[offset:idx+1], and advances offset past it; errors if delim not found.
59+
// readSlice reads until the first occurrence of delim, returning a slice
60+
// containing the data up to and including the delimiter, and advances offset
61+
// past it; errors if delim not found.
6162
func (s *streamingByteSrc) readSlice(delim byte) ([]byte, error) {
62-
data, err := s.br.ReadSlice(delim)
63-
if err != nil {
64-
return nil, err
63+
var full [][]byte
64+
var frag []byte
65+
var err error
66+
var n int
67+
68+
for {
69+
if l := len(frag); l > 0 {
70+
// Make a copy of the fragment to accumulate full buffers.
71+
buf := make([]byte, l)
72+
copy(buf, frag)
73+
full = append(full, buf)
74+
}
75+
frag, err = s.br.ReadSlice(delim)
76+
n += len(frag)
77+
if err != bufio.ErrBufferFull {
78+
break
79+
}
80+
}
81+
s.offset += int64(n)
82+
83+
// If ReadSlice is only called once, we can return the fragment directly.
84+
if len(full) == 0 {
85+
return frag, err
86+
}
87+
88+
// Allocate new buffer to hold the full buffers and the fragment.
89+
buf := make([]byte, n)
90+
n = 0
91+
for i := range full {
92+
n += copy(buf[n:], full[i])
6593
}
66-
s.offset += int64(len(data))
67-
return data, nil
94+
copy(buf[n:], frag)
95+
return buf, err
6896
}
6997

7098
// pos returns the current read position in the buffer.

bson/unmarshaling_cases_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
package bson
88

99
import (
10+
"fmt"
1011
"reflect"
12+
"strings"
1113
)
1214

1315
type unmarshalingTestCase struct {
@@ -58,6 +60,15 @@ func unmarshalingTestCases() []unmarshalingTestCase {
5860
Foo []byte
5961
}
6062

63+
longKey := strings.Repeat("k", 16_000_000)
64+
tLongKey := reflect.StructOf([]reflect.StructField{
65+
{
66+
Name: "Foo",
67+
Type: reflect.TypeOf(false),
68+
Tag: reflect.StructTag(fmt.Sprintf(`bson:"%s"`, longKey)),
69+
},
70+
})
71+
6172
return []unmarshalingTestCase{
6273
{
6374
name: "small struct",
@@ -235,6 +246,16 @@ func unmarshalingTestCases() []unmarshalingTestCase {
235246
{Key: "b_ptr_tracker", Value: MaxKey{}},
236247
}),
237248
},
249+
{
250+
name: "long key",
251+
sType: tLongKey,
252+
want: func() any {
253+
vLongKey := reflect.New(tLongKey)
254+
vLongKey.Elem().Field(0).SetBool(true)
255+
return vLongKey.Interface()
256+
}(),
257+
data: docToBytes(D{{longKey, true}}),
258+
},
238259
}
239260
}
240261

0 commit comments

Comments
 (0)