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:
parent
8383178c89
commit
b20904f574
3 changed files with 83 additions and 4 deletions
|
|
@ -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
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/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...)
|
||||
}
|
||||
Loading…
Reference in a new issue