commit 5d576d6e2e8d5991f65837611dbdd54a942e79f6
parent cc21d73a8fa3d9e51582b80b8bddfc472c864df2
Author: francois.parquet <francois.parquet@lalamove.com>
Date: Wed, 8 Aug 2018 14:33:14 +0800
fix bug on escape sequence when skiping object or array
Diffstat:
4 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/decode_array.go b/decode_array.go
@@ -79,26 +79,34 @@ func (dec *Decoder) skipArray() (int, error) {
arraysOpen++
case '"':
j++
+ var isInEscapeSeq bool
+ var isFirstQuote = true
for ; j < dec.length || dec.read(); j++ {
if dec.data[j] != '"' {
continue
}
- if dec.data[j-1] != '\\' {
+ if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) {
break
+ } else {
+ isInEscapeSeq = false
+ }
+ if isFirstQuote {
+ isFirstQuote = false
}
// loop backward and count how many anti slash found
// to see if string is effectively escaped
- ct := 1
- for i := j - 2; i > 0; i-- {
+ ct := 0
+ for i := j - 1; i > 0; i-- {
if dec.data[i] != '\\' {
break
}
ct++
}
- // is even number of slashes, quote is not escaped
+ // is pair number of slashes, quote is not escaped
if ct&1 == 0 {
break
}
+ isInEscapeSeq = true
}
default:
continue
diff --git a/decode_array_test.go b/decode_array_test.go
@@ -510,10 +510,12 @@ func TestUnmarshalJSONArrays(t *testing.T) {
func TestSkipArray(t *testing.T) {
testCases := []struct {
+ name string
json string
expectations func(*testing.T, int, error)
}{
{
+ name: "basic",
json: `"testbasic"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"testbasic"]`), i)
@@ -521,6 +523,7 @@ func TestSkipArray(t *testing.T) {
},
},
{
+ name: "complex escape string",
json: `"test \\\\\" escape"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"test \\\\\" escape"]`), i)
@@ -528,6 +531,7 @@ func TestSkipArray(t *testing.T) {
},
},
{
+ name: "complex escape slash",
json: `"test \\\\\\"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"test \\\\\\"]`), i)
@@ -544,9 +548,11 @@ func TestSkipArray(t *testing.T) {
}
for _, test := range testCases {
- dec := NewDecoder(strings.NewReader(test.json))
- i, err := dec.skipArray()
- test.expectations(t, i, err)
+ t.Run(test.name, func(t *testing.T) {
+ dec := NewDecoder(strings.NewReader(test.json))
+ i, err := dec.skipArray()
+ test.expectations(t, i, err)
+ })
}
}
diff --git a/decode_object.go b/decode_object.go
@@ -116,16 +116,23 @@ func (dec *Decoder) skipObject() (int, error) {
objectsOpen++
case '"':
j++
+ var isInEscapeSeq bool
+ var isFirstQuote = true
for ; j < dec.length || dec.read(); j++ {
if dec.data[j] != '"' {
continue
}
- if dec.data[j-1] != '\\' {
+ if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) {
break
+ } else {
+ isInEscapeSeq = false
+ }
+ if isFirstQuote {
+ isFirstQuote = false
}
// loop backward and count how many anti slash found
// to see if string is effectively escaped
- ct := 1
+ ct := 0
for i := j - 1; i > 0; i-- {
if dec.data[i] != '\\' {
break
@@ -134,8 +141,9 @@ func (dec *Decoder) skipObject() (int, error) {
}
// is pair number of slashes, quote is not escaped
if ct&1 == 0 {
- continue
+ break
}
+ isInEscapeSeq = true
}
default:
continue
diff --git a/decode_object_test.go b/decode_object_test.go
@@ -1370,7 +1370,7 @@ func TestSkipObject(t *testing.T) {
},
{
name: "basic-escaped",
- json: `"key":"value\\\\\\" hello"}`,
+ json: `"key":"value\\\\\\\" hello"}`,
},
{
name: "basic-err",