From e38c3606b3daa474e416864f13fe78da84a763a6 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 29 Mar 2021 02:28:04 +0900 Subject: [PATCH 1/3] Fix decoding of slice pointer type --- decode_slice.go | 8 ++++++-- decode_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/decode_slice.go b/decode_slice.go index 0442a75..e70588e 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -114,7 +114,9 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er dst := sliceHeader{data: data, len: idx, cap: capacity} copySlice(d.elemType, dst, src) } - if err := d.valueDecoder.decodeStream(s, depth, unsafe.Pointer(uintptr(data)+uintptr(idx)*d.size)); err != nil { + ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) + *(*unsafe.Pointer)(ep) = nil // initialize elem pointer + if err := d.valueDecoder.decodeStream(s, depth, ep); err != nil { return err } s.skipWhiteSpace() @@ -224,7 +226,9 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) dst := sliceHeader{data: data, len: idx, cap: capacity} copySlice(d.elemType, dst, src) } - c, err := d.valueDecoder.decode(buf, cursor, depth, unsafe.Pointer(uintptr(data)+uintptr(idx)*d.size)) + ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) + *(*unsafe.Pointer)(ep) = nil // initialize elem pointer + c, err := d.valueDecoder.decode(buf, cursor, depth, ep) if err != nil { return 0, err } diff --git a/decode_test.go b/decode_test.go index d76cf5c..6595f4b 100644 --- a/decode_test.go +++ b/decode_test.go @@ -14,6 +14,7 @@ import ( "strings" "testing" "time" + "unsafe" "github.com/goccy/go-json" ) @@ -2903,3 +2904,28 @@ func TestUnmarshalMaxDepth(t *testing.T) { } } } + +func TestDecodeSlice(t *testing.T) { + type B struct{ Int int32 } + type A struct{ B *B } + type X struct{ A []*A } + + w1 := &X{} + w2 := &X{} + + if err := json.Unmarshal([]byte(`{"a": [ {"b":{"int": 42} } ] }`), w1); err != nil { + t.Fatal(err) + } + w1addr := uintptr(unsafe.Pointer(w1.A[0].B)) + + if err := json.Unmarshal([]byte(`{"a": [ {"b":{"int": 112} } ] }`), w2); err != nil { + t.Fatal(err) + } + if uintptr(unsafe.Pointer(w1.A[0].B)) != w1addr { + t.Fatal("wrong addr") + } + w2addr := uintptr(unsafe.Pointer(w2.A[0].B)) + if w1addr == w2addr { + t.Fatal("invaid address") + } +} From e660ae468de69b0649edb02860137b3a0093fd3d Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 29 Mar 2021 02:44:49 +0900 Subject: [PATCH 2/3] Fix pointer alignment error --- decode_slice.go | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/decode_slice.go b/decode_slice.go index e70588e..d9a6749 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -7,12 +7,13 @@ import ( ) type sliceDecoder struct { - elemType *rtype - valueDecoder decoder - size uintptr - arrayPool sync.Pool - structName string - fieldName string + elemType *rtype + isElemPointerType bool + valueDecoder decoder + size uintptr + arrayPool sync.Pool + structName string + fieldName string } // If use reflect.SliceHeader, data type is uintptr. @@ -30,9 +31,10 @@ const ( func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fieldName string) *sliceDecoder { return &sliceDecoder{ - valueDecoder: dec, - elemType: elemType, - size: size, + valueDecoder: dec, + elemType: elemType, + isElemPointerType: elemType.Kind() == reflect.Ptr, + size: size, arrayPool: sync.Pool{ New: func() interface{} { return &sliceHeader{ @@ -115,7 +117,9 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er copySlice(d.elemType, dst, src) } ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) - *(*unsafe.Pointer)(ep) = nil // initialize elem pointer + if d.isElemPointerType { + *(*unsafe.Pointer)(ep) = nil // initialize elem pointer + } if err := d.valueDecoder.decodeStream(s, depth, ep); err != nil { return err } @@ -227,7 +231,9 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) copySlice(d.elemType, dst, src) } ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) - *(*unsafe.Pointer)(ep) = nil // initialize elem pointer + if d.isElemPointerType { + *(*unsafe.Pointer)(ep) = nil // initialize elem pointer + } c, err := d.valueDecoder.decode(buf, cursor, depth, ep) if err != nil { return 0, err From bfbfa474d6f31989754ae6510f9b0d96f9bd7b53 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 29 Mar 2021 02:57:41 +0900 Subject: [PATCH 3/3] Add map type to initialize type list --- decode_slice.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/decode_slice.go b/decode_slice.go index d9a6749..ea09f88 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -33,7 +33,7 @@ func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fie return &sliceDecoder{ valueDecoder: dec, elemType: elemType, - isElemPointerType: elemType.Kind() == reflect.Ptr, + isElemPointerType: elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Map, size: size, arrayPool: sync.Pool{ New: func() interface{} {