mirror of https://github.com/goccy/go-json.git
Merge pull request #167 from goccy/feature/fix-slice-decoder
Fix decoding of slice of pointer type
This commit is contained in:
commit
bcb5c87011
|
@ -7,12 +7,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type sliceDecoder struct {
|
type sliceDecoder struct {
|
||||||
elemType *rtype
|
elemType *rtype
|
||||||
valueDecoder decoder
|
isElemPointerType bool
|
||||||
size uintptr
|
valueDecoder decoder
|
||||||
arrayPool sync.Pool
|
size uintptr
|
||||||
structName string
|
arrayPool sync.Pool
|
||||||
fieldName string
|
structName string
|
||||||
|
fieldName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// If use reflect.SliceHeader, data type is uintptr.
|
// 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 {
|
func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fieldName string) *sliceDecoder {
|
||||||
return &sliceDecoder{
|
return &sliceDecoder{
|
||||||
valueDecoder: dec,
|
valueDecoder: dec,
|
||||||
elemType: elemType,
|
elemType: elemType,
|
||||||
size: size,
|
isElemPointerType: elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Map,
|
||||||
|
size: size,
|
||||||
arrayPool: sync.Pool{
|
arrayPool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
return &sliceHeader{
|
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}
|
dst := sliceHeader{data: data, len: idx, cap: capacity}
|
||||||
copySlice(d.elemType, dst, src)
|
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
|
return err
|
||||||
}
|
}
|
||||||
s.skipWhiteSpace()
|
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}
|
dst := sliceHeader{data: data, len: idx, cap: capacity}
|
||||||
copySlice(d.elemType, dst, src)
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goccy/go-json"
|
"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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue