From e38c3606b3daa474e416864f13fe78da84a763a6 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 29 Mar 2021 02:28:04 +0900 Subject: [PATCH] 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") + } +}