Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3585ae1

Browse files
authoredMay 23, 2023
fix: quote empty string key in ast (bytedance#427)
* fix: quote empty string key in ast * test: enhance ast fuzz * fix: unquote as default encoding json
1 parent f1a9b94 commit 3585ae1

File tree

4 files changed

+29
-6
lines changed

4 files changed

+29
-6
lines changed
 

‎ast/api_amd64.go

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func quote(buf *[]byte, val string) {
3737
*buf = append(*buf, '"')
3838
if len(val) == 0 {
3939
*buf = append(*buf, '"')
40+
return
4041
}
4142

4243
sp := rt.IndexChar(val, 0)

‎ast/encode_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ func TestEncodeValue(t *testing.T) {
8888
{NewString(`\"\"`), `"\\\"\\\""`, false},
8989
{NewString(_TwitterJson), string(quote), false},
9090
{NewArray([]Node{}), "[]", false},
91+
{NewArray([]Node{NewString(""), NewNull()}), `["",null]`, false},
9192
{NewArray([]Node{NewBool(true), NewString("true"), NewString("\t")}), `[true,"true","\t"]`, false},
9293
{NewObject([]Pair{Pair{"a", NewNull()}, Pair{"b", NewNumber("0")}}), `{"a":null,"b":0}`, false},
9394
{NewObject([]Pair{Pair{"\ta", NewString("\t")}, Pair{"\bb", NewString("\b")}, Pair{"\nb", NewString("\n")}, Pair{"\ra", NewString("\r")}}),`{"\ta":"\t","\u0008b":"\u0008","\nb":"\n","\ra":"\r"}`, false},
9495
{NewObject([]Pair{}), `{}`, false},
96+
{NewObject([]Pair{Pair{Key: "", Value: NewNull()}}), `{"":null}`, false},
9597
{NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, false},
9698
{NewAny(obj), string(buf), false},
9799
{NewRaw(`[{ }]`), "[{}]", false},

‎fuzz/fuzz_test.go

+22-5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ func FuzzMain(f *testing.F) {
4646
// Used for debug falied fuzz corpus
4747
func TestCorpus(t *testing.T) {
4848
fuzzMain(t, []byte("[1\x00"))
49+
fuzzMain(t, []byte("\"\\uDE1D\\uDE1D\\uDEDD\\uDE1D\\uDE1D\\uDE1D\\uDE1D\\uDEDD\\uDE1D\""))
50+
// fuzzMain(t, []byte(`{"":null}`))
4951
}
5052

5153
var target = sonic.ConfigStd
@@ -59,7 +61,7 @@ func fuzzMain(t *testing.T, data []byte) {
5961
if !json.Valid(data) {
6062
return
6163
}
62-
for _, typ := range []func() interface{}{
64+
for i, typ := range []func() interface{}{
6365
func() interface{} { return new(interface{}) },
6466
func() interface{} { return new(map[string]interface{}) },
6567
func() interface{} { return new([]interface{}) },
@@ -70,9 +72,10 @@ func fuzzMain(t *testing.T, data []byte) {
7072
// func() interface{} { return new(json.Number) },
7173
// func() interface{} { return new(S) },
7274
} {
73-
sv, jv := typ(), typ()
74-
serr := target.Unmarshal([]byte(data), sv)
75-
jerr := json.Unmarshal([]byte(data), jv)
75+
var sv = typ()
76+
var jv = typ()
77+
serr := target.Unmarshal(data, sv)
78+
jerr := json.Unmarshal(data, jv)
7679
require.Equal(t, serr != nil, jerr != nil,
7780
dump(data, jv, jerr, sv, serr))
7881
if jerr != nil {
@@ -87,7 +90,7 @@ func fuzzMain(t *testing.T, data []byte) {
8790
require.NoError(t, jerr, dump(v, jout, jerr, sout, serr))
8891

8992
{
90-
sv, jv := typ(), typ()
93+
sv, jv = typ(), typ()
9194
serr := target.Unmarshal(sout, sv)
9295
jerr := json.Unmarshal(jout, jv)
9396
require.Equalf(t, serr != nil, jerr != nil, dump(data, jv, jerr, sv, serr))
@@ -97,6 +100,20 @@ func fuzzMain(t *testing.T, data []byte) {
97100
require.Equal(t, sv, jv, dump(data, jv, jerr, sv, serr))
98101
}
99102

103+
// fuzz ast MarshalJSON API
104+
if i == 0 {
105+
root, aerr := sonic.Get(data)
106+
require.Equal(t, aerr, nil)
107+
aerr = root.LoadAll()
108+
require.Equal(t, aerr, nil, dump(data, jv, jerr, root, aerr))
109+
aout, aerr := root.MarshalJSON()
110+
require.Equal(t, aerr, nil)
111+
sv = typ()
112+
serr := json.Unmarshal(aout, sv)
113+
require.Equal(t, serr, nil)
114+
require.Equal(t, sv, jv, dump(data, jv, jerr, sv, serr))
115+
}
116+
100117
if m, ok := sv.(*map[string]interface{}); ok {
101118
fuzzDynamicStruct(t, jout, *m)
102119
fuzzASTGetFromObject(t, jout, *m)

‎unquote/unquote.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package unquote
1818

1919
import (
2020
`unsafe`
21+
`runtime`
2122

2223
`github.com/bytedance/sonic/internal/native`
2324
`github.com/bytedance/sonic/internal/native/types`
@@ -43,7 +44,8 @@ func intoBytesUnsafe(s string, m *[]byte) types.ParsingError {
4344
pos := -1
4445
slv := (*rt.GoSlice)(unsafe.Pointer(m))
4546
str := (*rt.GoString)(unsafe.Pointer(&s))
46-
ret := native.Unquote(str.Ptr, str.Len, slv.Ptr, &pos, 0)
47+
/* unquote as the default configuration, replace invalid unicode with \ufffd */
48+
ret := native.Unquote(str.Ptr, str.Len, slv.Ptr, &pos, types.F_UNICODE_REPLACE)
4749

4850
/* check for errors */
4951
if ret < 0 {
@@ -52,5 +54,6 @@ func intoBytesUnsafe(s string, m *[]byte) types.ParsingError {
5254

5355
/* update the length */
5456
slv.Len = ret
57+
runtime.KeepAlive(s)
5558
return 0
5659
}

0 commit comments

Comments
 (0)
Please sign in to comment.