From d88eb0986ea5e87f7970e91b4c873ecdd5c2c2c3 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 15 Dec 2020 12:29:19 +0900 Subject: [PATCH] Fix UnmarshalTypeError for int decoder --- decode_compile.go | 30 +++++++++++++++--------------- decode_int.go | 33 +++++++++++++++++++++++++++++---- decode_unmarshal_json.go | 34 ++++++++++------------------------ encode_compile.go | 2 ++ 4 files changed, 56 insertions(+), 43 deletions(-) diff --git a/decode_compile.go b/decode_compile.go index 1bbfe7c..3fd8396 100644 --- a/decode_compile.go +++ b/decode_compile.go @@ -44,15 +44,15 @@ func (d *Decoder) compile(typ *rtype, structName, fieldName string) (decoder, er case reflect.Uintptr: return d.compileUint(structName, fieldName) case reflect.Int: - return d.compileInt(structName, fieldName) + return d.compileInt(typ, structName, fieldName) case reflect.Int8: - return d.compileInt8(structName, fieldName) + return d.compileInt8(typ, structName, fieldName) case reflect.Int16: - return d.compileInt16(structName, fieldName) + return d.compileInt16(typ, structName, fieldName) case reflect.Int32: - return d.compileInt32(structName, fieldName) + return d.compileInt32(typ, structName, fieldName) case reflect.Int64: - return d.compileInt64(structName, fieldName) + return d.compileInt64(typ, structName, fieldName) case reflect.Uint: return d.compileUint(structName, fieldName) case reflect.Uint8: @@ -104,32 +104,32 @@ func (d *Decoder) compilePtr(typ *rtype, structName, fieldName string) (decoder, return newPtrDecoder(dec, typ.Elem(), structName, fieldName), nil } -func (d *Decoder) compileInt(structName, fieldName string) (decoder, error) { - return newIntDecoder(structName, fieldName, func(p unsafe.Pointer, v int64) { +func (d *Decoder) compileInt(typ *rtype, structName, fieldName string) (decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int)(p) = int(v) }), nil } -func (d *Decoder) compileInt8(structName, fieldName string) (decoder, error) { - return newIntDecoder(structName, fieldName, func(p unsafe.Pointer, v int64) { +func (d *Decoder) compileInt8(typ *rtype, structName, fieldName string) (decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int8)(p) = int8(v) }), nil } -func (d *Decoder) compileInt16(structName, fieldName string) (decoder, error) { - return newIntDecoder(structName, fieldName, func(p unsafe.Pointer, v int64) { +func (d *Decoder) compileInt16(typ *rtype, structName, fieldName string) (decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int16)(p) = int16(v) }), nil } -func (d *Decoder) compileInt32(structName, fieldName string) (decoder, error) { - return newIntDecoder(structName, fieldName, func(p unsafe.Pointer, v int64) { +func (d *Decoder) compileInt32(typ *rtype, structName, fieldName string) (decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int32)(p) = int32(v) }), nil } -func (d *Decoder) compileInt64(structName, fieldName string) (decoder, error) { - return newIntDecoder(structName, fieldName, func(p unsafe.Pointer, v int64) { +func (d *Decoder) compileInt64(typ *rtype, structName, fieldName string) (decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int64)(p) = v }), nil } diff --git a/decode_int.go b/decode_int.go index ee6886c..36874ce 100644 --- a/decode_int.go +++ b/decode_int.go @@ -1,17 +1,42 @@ package json import ( + "fmt" "unsafe" ) type intDecoder struct { + typ *rtype op func(unsafe.Pointer, int64) structName string fieldName string } -func newIntDecoder(structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder { - return &intDecoder{op: op, structName: structName, fieldName: fieldName} +func newIntDecoder(typ *rtype, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder { + return &intDecoder{ + typ: typ, + op: op, + structName: structName, + fieldName: fieldName, + } +} + +func (d *intDecoder) typeError(buf []byte, offset int64) *UnmarshalTypeError { + return &UnmarshalTypeError{ + Value: fmt.Sprintf("number %s", string(buf)), + Type: rtype2type(d.typ), + Offset: offset, + } +} + +func (d *intDecoder) annotateError(cursor int64, err error) { + switch e := err.(type) { + case *UnmarshalTypeError: + e.Struct = d.structName + e.Field = d.fieldName + case *SyntaxError: + e.Offset = cursor + } } var ( @@ -102,7 +127,7 @@ func (d *intDecoder) decodeStreamByte(s *stream) ([]byte, error) { } goto ERROR default: - goto ERROR + return nil, d.typeError([]byte{s.char()}, s.totalOffset()) } } ERROR: @@ -126,7 +151,7 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) num := buf[start:cursor] return num, cursor, nil default: - return nil, 0, errInvalidCharacter(buf[cursor], "number(integer)", cursor) + return nil, 0, d.typeError([]byte{buf[cursor]}, cursor) } } return nil, 0, errUnexpectedEndOfJSON("number(integer)", cursor) diff --git a/decode_unmarshal_json.go b/decode_unmarshal_json.go index 2674a07..7383738 100644 --- a/decode_unmarshal_json.go +++ b/decode_unmarshal_json.go @@ -5,10 +5,9 @@ import ( ) type unmarshalJSONDecoder struct { - typ *rtype - isDoublePointer bool - structName string - fieldName string + typ *rtype + structName string + fieldName string } func newUnmarshalJSONDecoder(typ *rtype, structName, fieldName string) *unmarshalJSONDecoder { @@ -58,26 +57,13 @@ func (d *unmarshalJSONDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer return 0, err } src := buf[start:end] - if d.isDoublePointer { - newptr := unsafe_New(d.typ.Elem()) - v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ - typ: d.typ, - ptr: newptr, - })) - if err := v.(Unmarshaler).UnmarshalJSON(src); err != nil { - d.annotateError(cursor, err) - return 0, err - } - *(*unsafe.Pointer)(p) = newptr - } else { - v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ - typ: d.typ, - ptr: p, - })) - if err := v.(Unmarshaler).UnmarshalJSON(src); err != nil { - d.annotateError(cursor, err) - return 0, err - } + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + typ: d.typ, + ptr: p, + })) + if err := v.(Unmarshaler).UnmarshalJSON(src); err != nil { + d.annotateError(cursor, err) + return 0, err } return end, nil } diff --git a/encode_compile.go b/encode_compile.go index defbddb..bd7e473 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -149,6 +149,8 @@ func (e *Encoder) compileKey(ctx *encodeCompileContext) (*opcode, error) { return e.compileUint32String(ctx) case reflect.Uint64: return e.compileUint64String(ctx) + case reflect.Uintptr: + return e.compileUintString(ctx) } return nil, &UnsupportedTypeError{Type: rtype2type(typ)} }