2
0
Fork 0
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:
duanyi.aster 2021-07-20 16:47:59 +08:00
parent a5efd7e8b7
commit 6b4022a19f
5 changed files with 79 additions and 72 deletions

View file

@ -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
}

View file

@ -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]
// }

View file

@ -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

View file

@ -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"} ] } `)

View file

@ -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)))