Fix cycle pointer value

This commit is contained in:
Masaaki Goshima 2020-08-20 23:56:12 +09:00
parent 51a1e71c6b
commit 7ac966b81e
2 changed files with 20 additions and 0 deletions

View File

@ -22,6 +22,7 @@ type Encoder struct {
indent int indent int
structTypeToCompiledCode map[uintptr]*compiledCode structTypeToCompiledCode map[uintptr]*compiledCode
structTypeToCompiledIndentCode map[uintptr]*compiledCode structTypeToCompiledIndentCode map[uintptr]*compiledCode
seenPtr map[uintptr]struct{}
} }
type compiledCode struct { type compiledCode struct {
@ -67,6 +68,7 @@ func init() {
buf: make([]byte, 0, bufSize), buf: make([]byte, 0, bufSize),
structTypeToCompiledCode: map[uintptr]*compiledCode{}, structTypeToCompiledCode: map[uintptr]*compiledCode{},
structTypeToCompiledIndentCode: map[uintptr]*compiledCode{}, structTypeToCompiledIndentCode: map[uintptr]*compiledCode{},
seenPtr: map[uintptr]struct{}{},
} }
}, },
} }

View File

@ -80,6 +80,13 @@ func (e *Encoder) run(code *opcode) error {
typ: ifaceCode.typ, typ: ifaceCode.typ,
ptr: unsafe.Pointer(ptr), ptr: unsafe.Pointer(ptr),
})) }))
if _, exists := e.seenPtr[ptr]; exists {
return &UnsupportedValueError{
Value: reflect.ValueOf(v),
Str: fmt.Sprintf("encountered a cycle via %s", code.typ),
}
}
e.seenPtr[ptr] = struct{}{}
rv := reflect.ValueOf(v) rv := reflect.ValueOf(v)
if rv.IsNil() { if rv.IsNil() {
e.encodeNull() e.encodeNull()
@ -498,6 +505,17 @@ func (e *Encoder) run(code *opcode) error {
code = c.next code = c.next
case opStructFieldRecursive: case opStructFieldRecursive:
recursive := code.toRecursiveCode() recursive := code.toRecursiveCode()
if _, exists := e.seenPtr[recursive.ptr]; exists {
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: code.typ,
ptr: unsafe.Pointer(recursive.ptr),
}))
return &UnsupportedValueError{
Value: reflect.ValueOf(v),
Str: fmt.Sprintf("encountered a cycle via %s", code.typ),
}
}
e.seenPtr[recursive.ptr] = struct{}{}
if err := e.run(newRecursiveCode(recursive)); err != nil { if err := e.run(newRecursiveCode(recursive)); err != nil {
return err return err
} }