Merge pull request #167 from goccy/feature/fix-slice-decoder

Fix decoding of slice of pointer type
This commit is contained in:
Masaaki Goshima 2021-03-29 03:11:36 +09:00 committed by GitHub
commit bcb5c87011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 11 deletions

View File

@ -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 || elemType.Kind() == reflect.Map,
size: size,
arrayPool: sync.Pool{
New: func() interface{} {
return &sliceHeader{
@ -114,7 +116,11 @@ 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)
if d.isElemPointerType {
*(*unsafe.Pointer)(ep) = nil // initialize elem pointer
}
if err := d.valueDecoder.decodeStream(s, depth, ep); err != nil {
return err
}
s.skipWhiteSpace()
@ -224,7 +230,11 @@ 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)
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
}

View File

@ -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")
}
}