mirror of
https://github.com/ii64/sonic.git
synced 2026-06-21 00:46:43 +08:00
fix: parser.ExportError() exceeds slice boundary
This commit is contained in:
parent
a5efd7e8b7
commit
6b4022a19f
5 changed files with 79 additions and 72 deletions
42
ast/node.go
42
ast/node.go
|
|
@ -514,10 +514,9 @@ func (self *Node) loadAllIndex() {
|
|||
parser, stack := self.getParserAndArrayStack()
|
||||
old := parser.noLazy
|
||||
parser.noLazy = true
|
||||
start := parser.p
|
||||
*self, err = parser.decodeArray(stack.v)
|
||||
if err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
parser.noLazy = old
|
||||
}
|
||||
|
|
@ -532,10 +531,9 @@ func (self *Node) skipAllIndex() {
|
|||
parser.skipValue = true
|
||||
oldl := parser.noLazy
|
||||
parser.noLazy = true
|
||||
start := parser.p
|
||||
*self, err = parser.decodeArray(stack.v)
|
||||
if err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
parser.skipValue = olds
|
||||
parser.noLazy = oldl
|
||||
|
|
@ -549,10 +547,9 @@ func (self *Node) loadAllKey() {
|
|||
parser, stack := self.getParserAndObjectStack()
|
||||
old := parser.noLazy
|
||||
parser.noLazy = true
|
||||
start := parser.p
|
||||
*self, err = parser.decodeObject(stack.v)
|
||||
if err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
parser.noLazy = old
|
||||
}
|
||||
|
|
@ -567,10 +564,9 @@ func (self *Node) skipAllKey() {
|
|||
parser.skipValue = true
|
||||
oldl := parser.noLazy
|
||||
parser.noLazy = true
|
||||
start := parser.p
|
||||
*self, err = parser.decodeObject(stack.v)
|
||||
if err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
parser.skipValue = olds
|
||||
parser.noLazy = oldl
|
||||
|
|
@ -604,11 +600,10 @@ func (self *Node) loadNextNode() *Node {
|
|||
parser := &stack.parser
|
||||
sp := parser.p
|
||||
ns := len(parser.s)
|
||||
start := sp
|
||||
|
||||
/* check for EOF */
|
||||
if parser.p = parser.lspace(sp); parser.p >= ns {
|
||||
panic(parser.ExportError(types.ERR_EOF, start))
|
||||
panic(parser.ExportError(types.ERR_EOF))
|
||||
}
|
||||
|
||||
/* check for empty array */
|
||||
|
|
@ -624,9 +619,8 @@ func (self *Node) loadNextNode() *Node {
|
|||
/* decode the value */
|
||||
old := parser.noLazy
|
||||
parser.noLazy = true
|
||||
start = parser.p
|
||||
if val, err = parser.Parse(); err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
parser.noLazy = old
|
||||
|
||||
|
|
@ -636,7 +630,7 @@ func (self *Node) loadNextNode() *Node {
|
|||
|
||||
/* check for EOF */
|
||||
if parser.p >= ns {
|
||||
panic(parser.ExportError(types.ERR_EOF, start))
|
||||
panic(parser.ExportError(types.ERR_EOF))
|
||||
}
|
||||
|
||||
/* check for the next character */
|
||||
|
|
@ -650,7 +644,7 @@ func (self *Node) loadNextNode() *Node {
|
|||
self.setArray(ret)
|
||||
return &ret[len(ret)-1]
|
||||
default:
|
||||
panic(parser.ExportError(types.ERR_INVALID_CHAR, start))
|
||||
panic(parser.ExportError(types.ERR_INVALID_CHAR))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -682,11 +676,10 @@ func (self *Node) loadNextPair() (*Pair) {
|
|||
parser := &stack.parser
|
||||
sp := parser.p
|
||||
ns := len(parser.s)
|
||||
start := sp
|
||||
|
||||
/* check for EOF */
|
||||
if parser.p = parser.lspace(sp); parser.p >= ns {
|
||||
panic(parser.ExportError(types.ERR_EOF, start))
|
||||
panic(parser.ExportError(types.ERR_EOF))
|
||||
}
|
||||
|
||||
/* check for empty object */
|
||||
|
|
@ -702,9 +695,8 @@ func (self *Node) loadNextPair() (*Pair) {
|
|||
var err types.ParsingError
|
||||
|
||||
/* decode the key */
|
||||
start = parser.p
|
||||
if njs = parser.decodeValue(); njs.Vt != types.V_STRING {
|
||||
panic(parser.ExportError(types.ERR_INVALID_CHAR, start))
|
||||
panic(parser.ExportError(types.ERR_INVALID_CHAR))
|
||||
}
|
||||
|
||||
/* extract the key */
|
||||
|
|
@ -714,22 +706,20 @@ func (self *Node) loadNextPair() (*Pair) {
|
|||
/* check for escape sequence */
|
||||
if njs.Ep != -1 {
|
||||
if key, err = unquote.String(key); err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
}
|
||||
|
||||
/* expect a ':' delimiter */
|
||||
start = parser.p
|
||||
if err = parser.delim(); err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
|
||||
/* decode the value */
|
||||
old := parser.noLazy
|
||||
parser.noLazy = true
|
||||
start = parser.p
|
||||
if val, err = parser.Parse(); err != 0 {
|
||||
panic(parser.ExportError(err, start))
|
||||
panic(parser.ExportError(err))
|
||||
}
|
||||
parser.noLazy = old
|
||||
|
||||
|
|
@ -739,7 +729,7 @@ func (self *Node) loadNextPair() (*Pair) {
|
|||
|
||||
/* check for EOF */
|
||||
if parser.p >= ns {
|
||||
panic(parser.ExportError(types.ERR_EOF, start))
|
||||
panic(parser.ExportError(types.ERR_EOF))
|
||||
}
|
||||
|
||||
/* check for the next character */
|
||||
|
|
@ -753,7 +743,7 @@ func (self *Node) loadNextPair() (*Pair) {
|
|||
self.setObject(ret)
|
||||
return &ret[len(ret)-1]
|
||||
default:
|
||||
panic(parser.ExportError(types.ERR_INVALID_CHAR, start))
|
||||
panic(parser.ExportError(types.ERR_INVALID_CHAR))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1015,7 +1005,7 @@ func (self *Node) parseRaw() Node {
|
|||
parser := NewParser(raw)
|
||||
n, e := parser.Parse()
|
||||
if e != 0 {
|
||||
panic(parser.ExportError(e, 0))
|
||||
panic(parser.ExportError(e))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,15 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`fmt`
|
||||
`sync`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/unquote`
|
||||
`github.com/bytedance/sonic/decoder`
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/unquote`
|
||||
)
|
||||
|
||||
const _DEFAULT_NODE_CAP int = 16
|
||||
|
|
@ -359,20 +360,27 @@ func NewParser(src string) *Parser {
|
|||
}
|
||||
|
||||
// ExportError converts types.ParsingError to std Error
|
||||
func (self *Parser) ExportError(err types.ParsingError, start int) error {
|
||||
func (self *Parser) ExportError(err types.ParsingError) error {
|
||||
if err == _ERR_NOT_FOUND {
|
||||
return fmt.Errorf("node not exists")
|
||||
}
|
||||
return fmt.Errorf("%v at %d, near '%s'", err, self.p, self.printNear(start))
|
||||
return fmt.Errorf("%q", decoder.SyntaxError{
|
||||
Pos: self.p,
|
||||
Src: self.s,
|
||||
Code: err,
|
||||
}.Description())
|
||||
}
|
||||
|
||||
func (self *Parser) printNear(start int) string {
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
end := self.p + 10
|
||||
if end > len(self.s) {
|
||||
end = len(self.s)
|
||||
}
|
||||
return self.s[start:end]
|
||||
}
|
||||
// func (self *Parser) printNear(start int) string {
|
||||
// end := self.p + 10
|
||||
// if end > len(self.s) {
|
||||
// end = len(self.s)
|
||||
// }
|
||||
// if start > end {
|
||||
// start = end - 1
|
||||
// }
|
||||
// if start < 0 {
|
||||
// start = 0
|
||||
// }
|
||||
// return self.s[start:end]
|
||||
// }
|
||||
|
|
@ -43,32 +43,30 @@ func (self *Searcher) GetByPath(path ...interface{}) (Node, error) {
|
|||
for _, p := range path {
|
||||
switch p.(type) {
|
||||
case int:
|
||||
start := self.parser.p
|
||||
if err = self.parser.searchIndex(p.(int)); err != 0 {
|
||||
return Node{}, self.parser.ExportError(err, start)
|
||||
return Node{}, self.parser.ExportError(err)
|
||||
}
|
||||
case string:
|
||||
start := self.parser.p
|
||||
if err = self.parser.searchKey(p.(string)); err != 0 {
|
||||
return Node{}, self.parser.ExportError(err, start)
|
||||
return Node{}, self.parser.ExportError(err)
|
||||
}
|
||||
default:
|
||||
panic("path must be either int or string")
|
||||
}
|
||||
}
|
||||
|
||||
var start int
|
||||
var start = self.parser.p
|
||||
if start, err = self.parser.skip(); err != 0 {
|
||||
return Node{}, self.parser.ExportError(err, start)
|
||||
return Node{}, self.parser.ExportError(err)
|
||||
}
|
||||
ns := len(self.parser.s)
|
||||
if self.parser.p > ns || start >= ns {
|
||||
if self.parser.p > ns || start >= ns || start>=self.parser.p {
|
||||
return Node{}, fmt.Errorf("skip %d char out of json boundary", start)
|
||||
}
|
||||
|
||||
t := switchRawType(self.parser.s[start])
|
||||
if t == _V_NONE {
|
||||
return Node{}, self.parser.ExportError(err, start)
|
||||
return Node{}, self.parser.ExportError(err)
|
||||
}
|
||||
|
||||
return newRawNode(self.parser.s[start:self.parser.p], t), nil
|
||||
|
|
|
|||
|
|
@ -24,6 +24,38 @@ import (
|
|||
`github.com/tidwall/gjson`
|
||||
)
|
||||
|
||||
func TestExportError(t *testing.T) {
|
||||
data := `{"a":]`
|
||||
p := NewSearcher(data)
|
||||
_, err := p.GetByPath("a")
|
||||
if err == nil {
|
||||
t.Fatal()
|
||||
}
|
||||
if err.Error() != `"Syntax error at index 6: invalid char\n\n\t{\"a\":]\n\t......^\n"` {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = `:"b"]`
|
||||
p = NewSearcher(data)
|
||||
_, err = p.GetByPath("a")
|
||||
if err == nil {
|
||||
t.Fatal()
|
||||
}
|
||||
if err.Error() != `"Syntax error at index 0: invalid char\n\n\t:\"b\"]\n\t^....\n"` {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = `{:"b"]`
|
||||
p = NewSearcher(data)
|
||||
_, err = p.GetByPath("a")
|
||||
if err == nil {
|
||||
t.Fatal()
|
||||
}
|
||||
if err.Error() != `"Syntax error at index 1: invalid char\n\n\t{:\"b\"]\n\t.^....\n"` {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearcher_GetByPath(t *testing.T) {
|
||||
s := NewSearcher(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import (
|
|||
`reflect`
|
||||
`testing`
|
||||
|
||||
`github.com/bytedance/sonic/ast`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/davecgh/go-spew/spew`
|
||||
`github.com/stretchr/testify/assert`
|
||||
|
|
@ -55,15 +54,6 @@ func TestGeneric_DecodeInterface(t *testing.T) {
|
|||
fmt.Printf("type: %s\n", reflect.TypeOf(v))
|
||||
}
|
||||
|
||||
func BenchmarkGeneric_DecodeAST(b *testing.B) {
|
||||
_, _, _ = ast.Loads(TwitterJson)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _ = ast.Loads(TwitterJson)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGeneric_DecodeGeneric(b *testing.B) {
|
||||
t := newStack()
|
||||
_, _, _ = decodeValue(t, TwitterJson, 0, 0)
|
||||
|
|
@ -75,17 +65,6 @@ func BenchmarkGeneric_DecodeGeneric(b *testing.B) {
|
|||
freeStack(t)
|
||||
}
|
||||
|
||||
func BenchmarkGeneric_Parallel_DecodeAST(b *testing.B) {
|
||||
_, _, _ = ast.Loads(TwitterJson)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, _, _ = ast.Loads(TwitterJson)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkGeneric_Parallel_DecodeGeneric(b *testing.B) {
|
||||
_, _, _ = decodeGeneric(TwitterJson, 0, 0)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
|
|
|
|||
Loading…
Reference in a new issue