forked from mirror/go-json
Fix decoding of embedded unexported pointer field
This commit is contained in:
parent
cf6cf56e3d
commit
6eb23deb6f
|
@ -1,8 +1,10 @@
|
||||||
package json
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -247,7 +249,7 @@ func decodeCompileInterface(typ *rtype, structName, fieldName string) (decoder,
|
||||||
return newInterfaceDecoder(typ, structName, fieldName), nil
|
return newInterfaceDecoder(typ, structName, fieldName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeRemoveConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, baseOffset uintptr) {
|
func decodeRemoveConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, field reflect.StructField) {
|
||||||
for k, v := range dec.fieldMap {
|
for k, v := range dec.fieldMap {
|
||||||
if _, exists := conflictedMap[k]; exists {
|
if _, exists := conflictedMap[k]; exists {
|
||||||
// already conflicted key
|
// already conflicted key
|
||||||
|
@ -257,7 +259,7 @@ func decodeRemoveConflictFields(fieldMap map[string]*structFieldSet, conflictedM
|
||||||
if !exists {
|
if !exists {
|
||||||
fieldSet := &structFieldSet{
|
fieldSet := &structFieldSet{
|
||||||
dec: v.dec,
|
dec: v.dec,
|
||||||
offset: baseOffset + v.offset,
|
offset: field.Offset + v.offset,
|
||||||
isTaggedKey: v.isTaggedKey,
|
isTaggedKey: v.isTaggedKey,
|
||||||
key: k,
|
key: k,
|
||||||
keyLen: int64(len(k)),
|
keyLen: int64(len(k)),
|
||||||
|
@ -281,7 +283,7 @@ func decodeRemoveConflictFields(fieldMap map[string]*structFieldSet, conflictedM
|
||||||
if v.isTaggedKey {
|
if v.isTaggedKey {
|
||||||
fieldSet := &structFieldSet{
|
fieldSet := &structFieldSet{
|
||||||
dec: v.dec,
|
dec: v.dec,
|
||||||
offset: baseOffset + v.offset,
|
offset: field.Offset + v.offset,
|
||||||
isTaggedKey: v.isTaggedKey,
|
isTaggedKey: v.isTaggedKey,
|
||||||
key: k,
|
key: k,
|
||||||
keyLen: int64(len(k)),
|
keyLen: int64(len(k)),
|
||||||
|
@ -318,6 +320,7 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD
|
||||||
if isIgnoredStructField(field) {
|
if isIgnoredStructField(field) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
isUnexportedField := unicode.IsLower([]rune(field.Name)[0])
|
||||||
tag := structTagFromField(field)
|
tag := structTagFromField(field)
|
||||||
dec, err := decodeCompile(type2rtype(field.Type), structName, field.Name, structTypeToDecoder)
|
dec, err := decodeCompile(type2rtype(field.Type), structName, field.Name, structTypeToDecoder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -329,13 +332,20 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD
|
||||||
// recursive definition
|
// recursive definition
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
decodeRemoveConflictFields(fieldMap, conflictedMap, stDec, field.Offset)
|
decodeRemoveConflictFields(fieldMap, conflictedMap, stDec, field)
|
||||||
} else if pdec, ok := dec.(*ptrDecoder); ok {
|
} else if pdec, ok := dec.(*ptrDecoder); ok {
|
||||||
contentDec := pdec.contentDecoder()
|
contentDec := pdec.contentDecoder()
|
||||||
if pdec.typ == typ {
|
if pdec.typ == typ {
|
||||||
// recursive definition
|
// recursive definition
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var fieldSetErr error
|
||||||
|
if isUnexportedField {
|
||||||
|
fieldSetErr = fmt.Errorf(
|
||||||
|
"json: cannot set embedded pointer to unexported struct: %v",
|
||||||
|
field.Type.Elem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
if dec, ok := contentDec.(*structDecoder); ok {
|
if dec, ok := contentDec.(*structDecoder); ok {
|
||||||
for k, v := range dec.fieldMap {
|
for k, v := range dec.fieldMap {
|
||||||
if _, exists := conflictedMap[k]; exists {
|
if _, exists := conflictedMap[k]; exists {
|
||||||
|
@ -350,6 +360,7 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD
|
||||||
isTaggedKey: v.isTaggedKey,
|
isTaggedKey: v.isTaggedKey,
|
||||||
key: k,
|
key: k,
|
||||||
keyLen: int64(len(k)),
|
keyLen: int64(len(k)),
|
||||||
|
err: fieldSetErr,
|
||||||
}
|
}
|
||||||
fieldMap[k] = fieldSet
|
fieldMap[k] = fieldSet
|
||||||
lower := strings.ToLower(k)
|
lower := strings.ToLower(k)
|
||||||
|
@ -374,6 +385,7 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD
|
||||||
isTaggedKey: v.isTaggedKey,
|
isTaggedKey: v.isTaggedKey,
|
||||||
key: k,
|
key: k,
|
||||||
keyLen: int64(len(k)),
|
keyLen: int64(len(k)),
|
||||||
|
err: fieldSetErr,
|
||||||
}
|
}
|
||||||
fieldMap[k] = fieldSet
|
fieldMap[k] = fieldSet
|
||||||
lower := strings.ToLower(k)
|
lower := strings.ToLower(k)
|
||||||
|
|
|
@ -15,6 +15,7 @@ type structFieldSet struct {
|
||||||
isTaggedKey bool
|
isTaggedKey bool
|
||||||
key string
|
key string
|
||||||
keyLen int64
|
keyLen int64
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
type structDecoder struct {
|
type structDecoder struct {
|
||||||
|
@ -524,6 +525,9 @@ func (d *structDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if field != nil {
|
if field != nil {
|
||||||
|
if field.err != nil {
|
||||||
|
return field.err
|
||||||
|
}
|
||||||
if err := field.dec.decodeStream(s, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
|
if err := field.dec.decodeStream(s, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -591,6 +595,9 @@ func (d *structDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int6
|
||||||
return 0, errExpected("object value after colon", cursor)
|
return 0, errExpected("object value after colon", cursor)
|
||||||
}
|
}
|
||||||
if field != nil {
|
if field != nil {
|
||||||
|
if field.err != nil {
|
||||||
|
return 0, field.err
|
||||||
|
}
|
||||||
c, err := field.dec.decode(buf, cursor, unsafe.Pointer(uintptr(p)+field.offset))
|
c, err := field.dec.decode(buf, cursor, unsafe.Pointer(uintptr(p)+field.offset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|
|
@ -2539,7 +2539,6 @@ func TestInvalidStringOption(t *testing.T) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
// Test unmarshal behavior with regards to embedded unexported structs.
|
// Test unmarshal behavior with regards to embedded unexported structs.
|
||||||
//
|
//
|
||||||
// (Issue 21357) If the embedded struct is a pointer and is unallocated,
|
// (Issue 21357) If the embedded struct is a pointer and is unallocated,
|
||||||
|
@ -2604,7 +2603,7 @@ func TestUnmarshalEmbeddedUnexported(t *testing.T) {
|
||||||
in: `{"R":2,"Q":1}`,
|
in: `{"R":2,"Q":1}`,
|
||||||
ptr: new(S1),
|
ptr: new(S1),
|
||||||
out: &S1{R: 2},
|
out: &S1{R: 2},
|
||||||
err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"),
|
err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json_test.embed1"),
|
||||||
}, {
|
}, {
|
||||||
// The top level Q field takes precedence.
|
// The top level Q field takes precedence.
|
||||||
in: `{"Q":1}`,
|
in: `{"Q":1}`,
|
||||||
|
@ -2626,7 +2625,7 @@ func TestUnmarshalEmbeddedUnexported(t *testing.T) {
|
||||||
in: `{"R":2,"Q":1}`,
|
in: `{"R":2,"Q":1}`,
|
||||||
ptr: new(S5),
|
ptr: new(S5),
|
||||||
out: &S5{R: 2},
|
out: &S5{R: 2},
|
||||||
err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"),
|
err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json_test.embed3"),
|
||||||
}, {
|
}, {
|
||||||
// Issue 24152, ensure decodeState.indirect does not panic.
|
// Issue 24152, ensure decodeState.indirect does not panic.
|
||||||
in: `{"embed1": {"Q": 1}}`,
|
in: `{"embed1": {"Q": 1}}`,
|
||||||
|
@ -2670,7 +2669,6 @@ func TestUnmarshalEmbeddedUnexported(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
|
func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue