Skip to content

Commit ffea80f

Browse files
author
tdakkota
committed
fix: do not reference buffer for key if decoder is buffered
Subsequent reads will change buffer and so, may overwrite the key.
1 parent aad4d90 commit ffea80f

File tree

4 files changed

+65
-10
lines changed

4 files changed

+65
-10
lines changed

dec_obj.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ func (d *Decoder) ObjBytes(f func(d *Decoder, key []byte) error) error {
2525
return d.decDepth()
2626
}
2727
d.unread()
28+
// Do not reference internal buffer for key if decoder is not buffered.
29+
//
30+
// Otherwise, subsequent reads may overwrite the key.
31+
//
32+
// See https://github.com/go-faster/jx/pull/62.
33+
isBuffer := d.reader == nil
2834

29-
k, err := d.str(value{raw: true})
35+
k, err := d.str(value{raw: isBuffer})
3036
if err != nil {
3137
return errors.Wrap(err, "str")
3238
}
@@ -47,7 +53,7 @@ func (d *Decoder) ObjBytes(f func(d *Decoder, key []byte) error) error {
4753
return errors.Wrap(err, "next")
4854
}
4955
for c == ',' {
50-
k, err := d.str(value{raw: true})
56+
k, err := d.str(value{raw: isBuffer})
5157
if err != nil {
5258
return errors.Wrap(err, "str")
5359
}

dec_obj_iter.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import "github.com/go-faster/errors"
44

55
// ObjIter is decoding object iterator.
66
type ObjIter struct {
7-
d *Decoder
8-
key []byte
9-
err error
10-
closed bool
11-
comma bool
7+
d *Decoder
8+
key []byte
9+
err error
10+
isBuffer bool
11+
closed bool
12+
comma bool
1213
}
1314

1415
// ObjIter creates new object iterator.
@@ -23,7 +24,7 @@ func (d *Decoder) ObjIter() (ObjIter, error) {
2324
return ObjIter{}, err
2425
}
2526
d.unread()
26-
return ObjIter{d: d}, nil
27+
return ObjIter{d: d, isBuffer: d.reader == nil}, nil
2728
}
2829

2930
// Key returns current key.
@@ -59,7 +60,7 @@ func (i *ObjIter) Next() bool {
5960
dec.unread()
6061
}
6162

62-
k, err := dec.str(value{raw: true})
63+
k, err := dec.str(value{raw: i.isBuffer})
6364
if err != nil {
6465
i.err = errors.Wrap(err, "str")
6566
return false

dec_obj_iter_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"io"
7+
"strings"
78
"testing"
89

910
"github.com/stretchr/testify/require"
@@ -76,3 +77,26 @@ func TestDecoder_ObjIter(t *testing.T) {
7677
a.Equal([]string{"foo", "bar", "baz"}, r)
7778
}))
7879
}
80+
81+
func TestDecoderObjIterIssue62(t *testing.T) {
82+
a := require.New(t)
83+
84+
const input = `{"1":1,"2":2}`
85+
86+
// Force decoder to read only first 4 bytes of input.
87+
d := Decode(strings.NewReader(input), 4)
88+
89+
iter, err := d.ObjIter()
90+
a.NoError(err)
91+
92+
actual := map[string]int{}
93+
for iter.Next() {
94+
val, err := d.Int()
95+
a.NoError(err)
96+
actual[string(iter.Key())] = val
97+
}
98+
a.Equal(map[string]int{
99+
"1": 1,
100+
"2": 2,
101+
}, actual)
102+
}

dec_obj_test.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package jx
22

33
import (
44
"encoding/json"
5+
"strings"
56
"testing"
67

78
"github.com/stretchr/testify/assert"
89
"github.com/stretchr/testify/require"
910
)
1011

11-
func TestDecoder_ObjectBytes(t *testing.T) {
12+
func TestDecoder_ObjBytes(t *testing.T) {
1213
t.Run("Object", func(t *testing.T) {
1314
i := DecodeStr(`{ "id" :1 , "randomNumber" : 10 }`)
1415
met := map[string]struct{}{}
@@ -62,3 +63,26 @@ func TestDecoder_ObjectBytes(t *testing.T) {
6263
}
6364
})
6465
}
66+
67+
func TestDecoderObjBytesIssue62(t *testing.T) {
68+
a := require.New(t)
69+
70+
const input = `{"1":1,"2":2}`
71+
72+
// Force decoder to read only first 4 bytes of input.
73+
d := Decode(strings.NewReader(input), 4)
74+
75+
actual := map[string]int{}
76+
a.NoError(d.ObjBytes(func(d *Decoder, key []byte) error {
77+
val, err := d.Int()
78+
if err != nil {
79+
return err
80+
}
81+
actual[string(key)] = val
82+
return nil
83+
}))
84+
a.Equal(map[string]int{
85+
"1": 1,
86+
"2": 2,
87+
}, actual)
88+
}

0 commit comments

Comments
 (0)