mirror of
https://github.com/ii64/sonic.git
synced 2026-06-23 18:06:44 +08:00
fix: check EOF after unmarshal
This commit is contained in:
parent
8383178c89
commit
b20904f574
3 changed files with 83 additions and 4 deletions
|
|
@ -30,20 +30,25 @@ const (
|
||||||
_F_disable_unknown
|
_F_disable_unknown
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Decoder is the decoder context object
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
i int
|
i int
|
||||||
f uint64
|
f uint64
|
||||||
s string
|
s string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDecoder creates a new decoder instance.
|
||||||
func NewDecoder(s string) *Decoder {
|
func NewDecoder(s string) *Decoder {
|
||||||
return &Decoder{s: s}
|
return &Decoder{s: s}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pos returns the current decoding position.
|
||||||
func (self *Decoder) Pos() int {
|
func (self *Decoder) Pos() int {
|
||||||
return self.i
|
return self.i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode parses the JSON-encoded data from current position and stores the result
|
||||||
|
// in the value pointed to by val.
|
||||||
func (self *Decoder) Decode(val interface{}) error {
|
func (self *Decoder) Decode(val interface{}) error {
|
||||||
vv := rt.UnpackEface(val)
|
vv := rt.UnpackEface(val)
|
||||||
vp := vv.Value
|
vp := vv.Value
|
||||||
|
|
@ -68,24 +73,35 @@ func (self *Decoder) Decode(val interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseInt64 causes the Decoder to unmarshal an integer into an interface{} as an
|
||||||
|
// int64 instead of as a float64.
|
||||||
func (self *Decoder) UseInt64() {
|
func (self *Decoder) UseInt64() {
|
||||||
self.f |= 1 << _F_use_int64
|
self.f |= 1 << _F_use_int64
|
||||||
self.f &^= 1 << _F_use_number
|
self.f &^= 1 << _F_use_number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
|
||||||
|
// json.Number instead of as a float64.
|
||||||
func (self *Decoder) UseNumber() {
|
func (self *Decoder) UseNumber() {
|
||||||
self.f &^= 1 << _F_use_int64
|
self.f &^= 1 << _F_use_int64
|
||||||
self.f |= 1 << _F_use_number
|
self.f |= 1 << _F_use_number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseUnicodeErrors causes the Decoder to return an error when encounter invalid
|
||||||
|
// UTF-8 escape sequences.
|
||||||
func (self *Decoder) UseUnicodeErrors() {
|
func (self *Decoder) UseUnicodeErrors() {
|
||||||
self.f |= 1 << _F_disable_urc
|
self.f |= 1 << _F_disable_urc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisallowUnknownFields causes the Decoder to return an error when the destination
|
||||||
|
// is a struct and the input contains object keys which do not match any
|
||||||
|
// non-ignored, exported fields in the destination.
|
||||||
func (self *Decoder) DisallowUnknownFields() {
|
func (self *Decoder) DisallowUnknownFields() {
|
||||||
self.f |= 1 << _F_disable_unknown
|
self.f |= 1 << _F_disable_unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
||||||
|
// order to reduce the first-hit latency.
|
||||||
func Pretouch(vt reflect.Type) (err error) {
|
func Pretouch(vt reflect.Type) (err error) {
|
||||||
_, err = findOrCompile(rt.UnpackType(vt))
|
_, err = findOrCompile(rt.UnpackType(vt))
|
||||||
return
|
return
|
||||||
|
|
|
||||||
32
issue67_test.go
Normal file
32
issue67_test.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 ByteDance Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonic
|
||||||
|
|
||||||
|
import (
|
||||||
|
`encoding/json`
|
||||||
|
`testing`
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIssue67_JunkAfterJSON(t *testing.T) {
|
||||||
|
data := `1e2e3`
|
||||||
|
var stdobj, sonicobj interface{}
|
||||||
|
stderr := json.Unmarshal([]byte(data), &stdobj)
|
||||||
|
sonicerr := Unmarshal([]byte(data), &sonicobj)
|
||||||
|
if (stderr == nil) != (sonicerr == nil) {
|
||||||
|
t.Fatalf("exp err: \n%#v, \ngot err: \n%#v\n", stderr, sonicerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
39
sonic.go
39
sonic.go
|
|
@ -23,6 +23,11 @@ import (
|
||||||
`github.com/bytedance/sonic/ast`
|
`github.com/bytedance/sonic/ast`
|
||||||
`github.com/bytedance/sonic/decoder`
|
`github.com/bytedance/sonic/decoder`
|
||||||
`github.com/bytedance/sonic/encoder`
|
`github.com/bytedance/sonic/encoder`
|
||||||
|
`github.com/bytedance/sonic/internal/native/types`
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_SpaceMask = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n')
|
||||||
)
|
)
|
||||||
|
|
||||||
// Marshal returns the JSON encoding of v.
|
// Marshal returns the JSON encoding of v.
|
||||||
|
|
@ -38,7 +43,33 @@ func Unmarshal(buf []byte, val interface{}) error {
|
||||||
|
|
||||||
// UnmarshalString is like Unmarshal, except buf is a string.
|
// UnmarshalString is like Unmarshal, except buf is a string.
|
||||||
func UnmarshalString(buf string, val interface{}) error {
|
func UnmarshalString(buf string, val interface{}) error {
|
||||||
return decoder.NewDecoder(buf).Decode(val)
|
dec := decoder.NewDecoder(buf)
|
||||||
|
err := dec.Decode(val)
|
||||||
|
pos := dec.Pos()
|
||||||
|
|
||||||
|
/* check for errors */
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip all the trailing spaces */
|
||||||
|
if pos != len(buf) {
|
||||||
|
for pos < len(buf) && (_SpaceMask & (1 << buf[pos])) != 0 {
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* then it must be at EOF */
|
||||||
|
if pos == len(buf) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* junk after JSON value */
|
||||||
|
return decoder.SyntaxError {
|
||||||
|
Src : buf,
|
||||||
|
Pos : dec.Pos(),
|
||||||
|
Code : types.ERR_INVALID_CHAR,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
||||||
|
|
@ -54,17 +85,17 @@ func Pretouch(vt reflect.Type) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get searches the given path json,
|
// Get searches the given path json,
|
||||||
// and returns its representing ast.Node
|
// and returns its representing ast.Node.
|
||||||
//
|
//
|
||||||
// Each path arg must be integer or string:
|
// Each path arg must be integer or string:
|
||||||
// - Integer means searching current node as array,
|
// - Integer means searching current node as array
|
||||||
// - String means searching current node as object
|
// - String means searching current node as object
|
||||||
func Get(src []byte, path ...interface{}) (ast.Node, error) {
|
func Get(src []byte, path ...interface{}) (ast.Node, error) {
|
||||||
return GetFromString(string(src), path...)
|
return GetFromString(string(src), path...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFromString is same with Get except src is string,
|
// GetFromString is same with Get except src is string,
|
||||||
// which can reduce unnecessary memory copy
|
// which can reduce unnecessary memory copy.
|
||||||
func GetFromString(src string, path ...interface{}) (ast.Node, error) {
|
func GetFromString(src string, path ...interface{}) (ast.Node, error) {
|
||||||
return ast.NewSearcher(src).GetByPath(path...)
|
return ast.NewSearcher(src).GetByPath(path...)
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue