Skip to content

Commit

Permalink
feat:(decoder) clear memory when decoding failed
Browse files Browse the repository at this point in the history
  • Loading branch information
AsterDY committed Nov 4, 2022
1 parent 02fe882 commit f2ee3ca
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 3 deletions.
9 changes: 7 additions & 2 deletions decode_test.go
@@ -1,3 +1,4 @@
//go:build amd64
// +build amd64

/*
Expand Down Expand Up @@ -34,12 +35,13 @@ import (
`strings`
`testing`
`time`
`unsafe`
`unicode/utf8`
`unsafe`

`github.com/bytedance/sonic/decoder`
`github.com/bytedance/sonic/internal/native/types`
`github.com/davecgh/go-spew/spew`
`github.com/stretchr/testify/assert`
)

type T struct {
Expand Down Expand Up @@ -1732,11 +1734,14 @@ func TestEmptyString(t *testing.T) {
Number2 int `json:",string"`
}
data := `{"Number1":"1", "Number2":""}`
var t2 T2
var t2, t3 T2
err := Unmarshal([]byte(data), &t2)
if err == nil {
t.Fatal("Decode: did not return error")
}
err2 := json.Unmarshal([]byte(data), &t3)
assert.Equal(t, err == nil, err2 == nil)
assert.Equal(t, t2, t3)
if t2.Number1 != 1 {
t.Fatal("Decode: did not set Number1")
}
Expand Down
15 changes: 15 additions & 0 deletions decoder/decoder.go
Expand Up @@ -20,6 +20,7 @@ import (
`encoding/json`
`reflect`
`runtime`
`unsafe`

`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
Expand Down Expand Up @@ -95,11 +96,25 @@ func (self *Decoder) Decode(val interface{}) error {
if vp == nil || vv.Type.Kind() != reflect.Ptr {
return &json.InvalidUnmarshalError{Type: vv.Type.Pack()}
}
initalized := (vv.Type.Pack().Elem().Kind() == reflect.Ptr) && (*(*unsafe.Pointer)(vp) != nil)

/* create a new stack, and call the decoder */
sb, etp := newStack(), rt.PtrElem(vv.Type)
nb, err := decodeTypedPointer(self.s, self.i, etp, vp, sb, self.f)

if err != nil {
// clear val memory when decode failed,
// not including MismatcheTypeError
if _, ok := err.(*MismatchTypeError); !ok {
ev := reflect.ValueOf(val).Elem()
if initalized {
ev.Elem().Set(reflect.Zero(ev.Elem().Type()))
} else {
ev.Set(reflect.Zero(ev.Type()))
}
}
}

/* return the stack back */
self.i = nb
freeStack(sb)
Expand Down
58 changes: 57 additions & 1 deletion decoder/decoder_test.go
Expand Up @@ -87,7 +87,7 @@ func init() {
}


func TestSkipError(t *testing.T) {
func TestSkipMismatchTypeError(t *testing.T) {
println("TestSkipError")
type skiptype struct {
A int `json:"a"`
Expand Down Expand Up @@ -132,6 +132,62 @@ func TestSkipError(t *testing.T) {
}
}

type testStruct struct {
A int `json:"a"`
B string `json:"b"`
}

func TestClearMemWhenError(t *testing.T) {
var data = `{"a":1,"b":"1"]`
var v, v2 testStruct
_, err := decode(data, &v, false)
err2 := json.Unmarshal([]byte(data), &v2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, v2, v)

var z, z2 = new(testStruct), new(testStruct)
_, err = decode(data, z, false)
err2 = json.Unmarshal([]byte(data), z2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, z2, z)

var y, y2 *testStruct
_, err = decode(data, &y, false)
err2 = json.Unmarshal([]byte(data), &y2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, y2, y)

var x, x2 = new(testStruct), new(testStruct)
_, err = decode(data, &x, false)
err2 = json.Unmarshal([]byte(data), &x2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, x2, x)

var a, a2 interface{}
_, err = decode(data, &a, false)
err2 = json.Unmarshal([]byte(data), &a2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, a2, a)

var b, b2 = new(interface{}), new(interface{})
_, err = decode(data, b, false)
err2 = json.Unmarshal([]byte(data), b2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, b2, b)

var c, c2 *interface{}
_, err = decode(data, &c, false)
err2 = json.Unmarshal([]byte(data), &c2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, c2, c)

var d, d2 = new(interface{}), new(interface{})
_, err = decode(data, &d, false)
err2 = json.Unmarshal([]byte(data), &d2)
assert.Equal(t, err2 == nil, err == nil)
assert.Equal(t, d2, d)
}

func TestDecodeCorrupt(t *testing.T) {
var ds = []string{
`{,}`,
Expand Down

0 comments on commit f2ee3ca

Please sign in to comment.