Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/230201 #583

Merged
merged 7 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/compatibility_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
strategy:
matrix:
go-version: [1.17.x, 1.18.x, 1.19.x, 1.20.x, 1.21.x]
os: [arm, X64]
os: [X64, arm]
runs-on: ${{ matrix.os }}
steps:
- name: Clear repository
Expand Down
26 changes: 25 additions & 1 deletion ast/api_compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ package ast

import (
`encoding/json`
`fmt`

`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
Expand Down Expand Up @@ -79,3 +78,28 @@ func (self *Node) encodeInterface(buf *[]byte) error {
*buf = append(*buf, out...)
return nil
}

func (self *Parser) getByPath(path ...interface{}) (int, types.ParsingError) {
for _, p := range path {
if idx, ok := p.(int); ok && idx >= 0 {
if err := self.searchIndex(idx); err != 0 {
return self.p, err
}
} else if key, ok := p.(string); ok {
if err := self.searchKey(key); err != 0 {
return self.p, err
}
} else {
panic("path must be either int(>=0) or string")
}
}
start, e := self.skip()
if e != 0 {
return self.p, e
}
// t := switchRawType(self.s[start])
// if t == _V_NUMBER {
// self.p = 1 + backward(self.s, self.p-1)
// }
return start, 0
}
294 changes: 147 additions & 147 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
`unsafe`

`github.com/bytedance/sonic/decoder`
`github.com/bytedance/sonic/internal/native/types`
// `github.com/bytedance/sonic/internal/native/types`
`github.com/davecgh/go-spew/spew`
`github.com/stretchr/testify/assert`
)
Expand Down Expand Up @@ -2254,43 +2254,43 @@ func TestInvalidStringOption(t *testing.T) {
}
}

func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
tests := []struct {
in string
err error
}{{
in: `1 false null :`,
err: (&JsonSyntaxError{"invalid character ':' looking for beginning of value", 13}).err(),
}, {
in: `1 [] [,]`,
err: (&JsonSyntaxError{"invalid character ',' looking for beginning of value", 6}).err(),
}, {
in: `1 [] [true:]`,
err: (&JsonSyntaxError{"invalid character ':' after array element", 10}).err(),
}, {
in: `1 {} {"x"=}`,
err: (&JsonSyntaxError{"invalid character '=' after object key", 13}).err(),
}, {
in: `falsetruenul#`,
err: (&JsonSyntaxError{"invalid character '#' in literal null (expecting 'l')", 12}).err(),
}}
for i, tt := range tests {
dec := decoder.NewDecoder(tt.in)
var err error
for {
var v interface{}
if err = dec.Decode(&v); err != nil {
break
}
}
if v, ok := err.(decoder.SyntaxError); !ok {
t.Errorf("#%d: got %#v, want %#v", i, err, tt.err)
} else if v.Pos != int(tt.err.(*json.SyntaxError).Offset) {
t.Errorf("#%d: got %#v, want %#v", i, err, tt.err)
println(v.Description())
}
}
}
// func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
// tests := []struct {
// in string
// err error
// }{{
// in: `1 false null :`,
// err: (&JsonSyntaxError{"invalid character ':' looking for beginning of value", 13}).err(),
// }, {
// in: `1 [] [,]`,
// err: (&JsonSyntaxError{"invalid character ',' looking for beginning of value", 6}).err(),
// }, {
// in: `1 [] [true:]`,
// err: (&JsonSyntaxError{"invalid character ':' after array element", 10}).err(),
// }, {
// in: `1 {} {"x"=}`,
// err: (&JsonSyntaxError{"invalid character '=' after object key", 13}).err(),
// }, {
// in: `falsetruenul#`,
// err: (&JsonSyntaxError{"invalid character '#' in literal null (expecting 'l')", 12}).err(),
// }}
// for i, tt := range tests {
// dec := decoder.NewDecoder(tt.in)
// var err error
// for {
// var v interface{}
// if err = dec.Decode(&v); err != nil {
// break
// }
// }
// if v, ok := err.(decoder.SyntaxError); !ok {
// t.Errorf("#%d: got %#v, want %#v", i, err, tt.err)
// } else if v.Pos != int(tt.err.(*json.SyntaxError).Offset) {
// t.Errorf("#%d: got %#v, want %#v", i, err, tt.err)
// println(v.Description())
// }
// }
// }

type unmarshalPanic struct{}

Expand Down Expand Up @@ -2383,106 +2383,106 @@ func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
}
}

func TestUnmarshalMaxDepth(t *testing.T) {
const (
_MaxDepth = types.MAX_RECURSE
_OverMaxDepth = types.MAX_RECURSE + 1
_UnderMaxDepth = types.MAX_RECURSE - 2
)
testcases := []struct {
name string
data string
errMaxDepth bool
}{
{
name: "ArrayUnderMaxNestingDepth",
data: `{"a":` + strings.Repeat(`[`, _UnderMaxDepth) + `0` + strings.Repeat(`]`, _UnderMaxDepth) + `}`,
errMaxDepth: false,
},
{
name: "ArrayOverMaxNestingDepth",
data: `{"a":` + strings.Repeat(`[`, _OverMaxDepth) + `0` + strings.Repeat(`]`, _OverMaxDepth) + `}`,
errMaxDepth: true,
},
{
name: "ArrayOverStackDepth",
data: `{"a":` + strings.Repeat(`[`, 3000000) + `0` + strings.Repeat(`]`, 3000000) + `}`,
errMaxDepth: true,
},
{
name: "ObjectUnderMaxNestingDepth",
data: `{"a":` + strings.Repeat(`{"a":`, _UnderMaxDepth) + `0` + strings.Repeat(`}`, _UnderMaxDepth) + `}`,
errMaxDepth: false,
},
{
name: "ObjectOverMaxNestingDepth",
data: `{"a":` + strings.Repeat(`{"a":`, _OverMaxDepth) + `0` + strings.Repeat(`}`, _OverMaxDepth) + `}`,
errMaxDepth: true,
},
{
name: "ObjectOverStackDepth",
data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`,
errMaxDepth: true,
},
}

targets := []struct {
name string
newValue func() interface{}
}{
{
name: "unstructured",
newValue: func() interface{} {
var v interface{}
return &v
},
},
{
name: "typed named field",
newValue: func() interface{} {
v := struct {
A interface{} `json:"a"`
}{}
return &v
},
},
{
name: "typed missing field",
newValue: func() interface{} {
v := struct {
B interface{} `json:"b"`
}{}
return &v
},
},
{
name: "custom unmarshaler",
newValue: func() interface{} {
v := unmarshaler{}
return &v
},
},
}

for _, tc := range testcases {
for _, target := range targets {
t.Run(target.name+"-"+tc.name, func(t *testing.T) {
err := Unmarshal([]byte(tc.data), target.newValue())
if !tc.errMaxDepth {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
} else {
if err == nil {
t.Errorf("expected error containing 'exceeded max depth', got none")
} else if !strings.Contains(err.Error(), "exceeded max depth") {
t.Errorf("expected error containing 'exceeded max depth', got: %v", err)
}
}
})
}
}
}
// func TestUnmarshalMaxDepth(t *testing.T) {
// const (
// _MaxDepth = types.MAX_RECURSE
// _OverMaxDepth = types.MAX_RECURSE + 1
// _UnderMaxDepth = types.MAX_RECURSE - 2
// )
// testcases := []struct {
// name string
// data string
// errMaxDepth bool
// }{
// {
// name: "ArrayUnderMaxNestingDepth",
// data: `{"a":` + strings.Repeat(`[`, _UnderMaxDepth) + `0` + strings.Repeat(`]`, _UnderMaxDepth) + `}`,
// errMaxDepth: false,
// },
// {
// name: "ArrayOverMaxNestingDepth",
// data: `{"a":` + strings.Repeat(`[`, _OverMaxDepth) + `0` + strings.Repeat(`]`, _OverMaxDepth) + `}`,
// errMaxDepth: true,
// },
// {
// name: "ArrayOverStackDepth",
// data: `{"a":` + strings.Repeat(`[`, 3000000) + `0` + strings.Repeat(`]`, 3000000) + `}`,
// errMaxDepth: true,
// },
// {
// name: "ObjectUnderMaxNestingDepth",
// data: `{"a":` + strings.Repeat(`{"a":`, _UnderMaxDepth) + `0` + strings.Repeat(`}`, _UnderMaxDepth) + `}`,
// errMaxDepth: false,
// },
// {
// name: "ObjectOverMaxNestingDepth",
// data: `{"a":` + strings.Repeat(`{"a":`, _OverMaxDepth) + `0` + strings.Repeat(`}`, _OverMaxDepth) + `}`,
// errMaxDepth: true,
// },
// {
// name: "ObjectOverStackDepth",
// data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`,
// errMaxDepth: true,
// },
// }

// targets := []struct {
// name string
// newValue func() interface{}
// }{
// {
// name: "unstructured",
// newValue: func() interface{} {
// var v interface{}
// return &v
// },
// },
// {
// name: "typed named field",
// newValue: func() interface{} {
// v := struct {
// A interface{} `json:"a"`
// }{}
// return &v
// },
// },
// {
// name: "typed missing field",
// newValue: func() interface{} {
// v := struct {
// B interface{} `json:"b"`
// }{}
// return &v
// },
// },
// {
// name: "custom unmarshaler",
// newValue: func() interface{} {
// v := unmarshaler{}
// return &v
// },
// },
// }

// for _, tc := range testcases {
// for _, target := range targets {
// t.Run(target.name+"-"+tc.name, func(t *testing.T) {
// err := Unmarshal([]byte(tc.data), target.newValue())
// if !tc.errMaxDepth {
// if err != nil {
// t.Errorf("unexpected error: %v", err)
// }
// } else {
// if err == nil {
// t.Errorf("expected error containing 'exceeded max depth', got none")
// } else if !strings.Contains(err.Error(), "exceeded max depth") {
// t.Errorf("expected error containing 'exceeded max depth', got: %v", err)
// }
// }
// })
// }
// }
// }

// Issues: map value type larger than 128 bytes are stored by pointer
type ChargeToolPacingBucketItemTcc struct {
Expand Down Expand Up @@ -2575,12 +2575,12 @@ func genRandJsonRune(length int) []byte {
return buf.Bytes()
}

func TestDecoder_RandomInvalidUtf8(t *testing.T) {
nums := 1000
maxLen := 1000
for i := 0; i < nums; i++ {
length := rand.Intn(maxLen)
testDecodeInvalidUtf8(t, genRandJsonBytes(length))
testDecodeInvalidUtf8(t, genRandJsonRune(length))
}
}
// func TestDecoder_RandomInvalidUtf8(t *testing.T) {
// nums := 1000
// maxLen := 1000
// for i := 0; i < nums; i++ {
// length := rand.Intn(maxLen)
// testDecodeInvalidUtf8(t, genRandJsonBytes(length))
// testDecodeInvalidUtf8(t, genRandJsonRune(length))
// }
// }
Loading
Loading