2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00

fix: check EOF after unmarshal

This commit is contained in:
chenzhuoyu 2021-08-16 18:57:04 +08:00 committed by Oxygen
parent 8383178c89
commit b20904f574
3 changed files with 83 additions and 4 deletions

View file

@ -30,20 +30,25 @@ const (
_F_disable_unknown
)
// Decoder is the decoder context object
type Decoder struct {
i int
f uint64
s string
}
// NewDecoder creates a new decoder instance.
func NewDecoder(s string) *Decoder {
return &Decoder{s: s}
}
// Pos returns the current decoding position.
func (self *Decoder) Pos() int {
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 {
vv := rt.UnpackEface(val)
vp := vv.Value
@ -68,24 +73,35 @@ func (self *Decoder) Decode(val interface{}) error {
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() {
self.f |= 1 << _F_use_int64
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() {
self.f &^= 1 << _F_use_int64
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() {
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() {
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) {
_, err = findOrCompile(rt.UnpackType(vt))
return

32
issue67_test.go Normal file
View 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)
}
}

View file

@ -23,6 +23,11 @@ import (
`github.com/bytedance/sonic/ast`
`github.com/bytedance/sonic/decoder`
`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.
@ -38,7 +43,33 @@ func Unmarshal(buf []byte, val interface{}) error {
// UnmarshalString is like Unmarshal, except buf is a string.
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
@ -54,17 +85,17 @@ func Pretouch(vt reflect.Type) error {
}
// 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:
// - Integer means searching current node as array,
// - Integer means searching current node as array
// - String means searching current node as object
func Get(src []byte, path ...interface{}) (ast.Node, error) {
return GetFromString(string(src), path...)
}
// 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) {
return ast.NewSearcher(src).GetByPath(path...)
}