Skip to content

Commit

Permalink
fix(aarch64): bugs when parsing json (#745)
Browse files Browse the repository at this point in the history
  • Loading branch information
liuq19 authored Feb 19, 2025
1 parent c1d33ce commit 51ef605
Show file tree
Hide file tree
Showing 85 changed files with 106,371 additions and 106,077 deletions.
12 changes: 8 additions & 4 deletions .github/workflows/fuzzing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ on: pull_request
jobs:
build:
strategy:
max-parallel: 2
matrix:
mode: [run, runopt]
os: [ubuntu-latest, ubuntu-24.04-arm]
exclude:
- os: ubuntu-24.04-arm
mode: runopt

runs-on: ${{ matrix.os }}
steps:
- name: Clear repository
Expand All @@ -27,7 +33,5 @@ jobs:
${{ runner.os }}-go-
- name: Fuzz sonic
run: |
cd ./fuzz
make fuzz
make runopt
run: ./scripts/fuzz.sh ${{ matrix.mode }}

35 changes: 21 additions & 14 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1133,10 +1133,28 @@ func TestMarshalEmbeds(t *testing.T) {

func TestUnmarshal(t *testing.T) {
for i, tt := range unmarshalTests {
if !json.Valid([]byte(tt.in)) {
continue
// construct decoder
dec := decoder.NewDecoder(tt.in)
if tt.useNumber {
dec.UseNumber()
}
if tt.disallowUnknownFields {
dec.DisallowUnknownFields()
}
if tt.validateString {
dec.ValidateString()
}
if tt.ptr == nil {

// check decode result for invalid jsons
if !json.Valid([]byte(tt.in)) || tt.ptr == nil {
var sv interface{}
err := dec.Decode(&sv)
if err == nil && tt.err != nil {
err = dec.CheckTrailings()
if err == nil && tt.err != nil {
t.Errorf("test json #%d: %v, %v, want %v", i, tt.in, err, tt.err)
}
}
continue
}

Expand All @@ -1147,7 +1165,6 @@ func TestUnmarshal(t *testing.T) {
}
typ = typ.Elem()

// v = new(right-type)
v := reflect.New(typ)

if !reflect.DeepEqual(tt.ptr, v.Interface()) {
Expand All @@ -1161,16 +1178,6 @@ func TestUnmarshal(t *testing.T) {
continue
}

dec := decoder.NewDecoder(tt.in)
if tt.useNumber {
dec.UseNumber()
}
if tt.disallowUnknownFields {
dec.DisallowUnknownFields()
}
if tt.validateString {
dec.ValidateString()
}
if err := dec.Decode(v.Interface()); (err == nil) != (tt.err == nil) {
spew.Dump(tt)
t.Fatalf("#%d: %v, want %v", i, err, tt.err)
Expand Down
19 changes: 0 additions & 19 deletions fuzz/Makefile

This file was deleted.

21 changes: 21 additions & 0 deletions fuzz/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,36 @@ func TestFuzzCases(t *testing.T) {

var target = sonic.ConfigStd

func fuzzInvalidJson(t *testing.T, data []byte) {
for _, typ := range []func() interface{}{
func() interface{} { return new(interface{}) },
func() interface{} { return new(map[string]interface{}) },
func() interface{} { return new([]interface{}) },
func() interface{} { return new(string) },
func() interface{} { return new(int64) },
func() interface{} { return new(uint64) },
func() interface{} { return new(float64) },
func() interface{} { return new(json.Number) },
func() interface{} { return new(S) },
} {
// to check memory corruption
var sv = typ()
_ = sonic.Unmarshal(data, sv)
}
}

func fuzzMain(t *testing.T, data []byte) {
fuzzValidate(t, data)
fuzzHtmlEscape(t, data)
// fuzz ast get api, should not panic here.
fuzzAst(t, data)

// Only fuzz the validate json here.
if !json.Valid(data) {
fuzzInvalidJson(t, data)
return
}

fuzzStream(t, data)
for i, typ := range []func() interface{}{
func() interface{} { return new(interface{}) },
Expand Down
7 changes: 4 additions & 3 deletions internal/decoder/optdec/native.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type nodeBuf struct {
depth uint64
nstart uintptr
nend uintptr
iskey bool
stat jsonStat
}

Expand Down Expand Up @@ -196,14 +197,14 @@ func (p *Parser) parse() ErrorCode {

// check OoB here
offset := p.nbuf.ncur - p.nbuf.nstart
curLen := offset / unsafe.Sizeof(node{})
if curLen != uintptr(len(p.nodes)) {
curLen := int(offset / unsafe.Sizeof(node{}))
if curLen != len(p.nodes) {
panic(fmt.Sprintf("current len: %d, real len: %d cap: %d", curLen, len(p.nodes), cap(p.nodes)))
}

// node buf is not enough, continue parse
// the maxCap is always meet all valid JSON
maxCap := calMaxNodeCap(len(p.Json))
maxCap := curLen + calMaxNodeCap(len(p.Json) - int(p.cur - p.start))
slice := rt.GoSlice{
Ptr: rt.Mallocgc(uintptr(maxCap) * nodeType.Size, nodeType, false),
Len: maxCap,
Expand Down
24 changes: 12 additions & 12 deletions internal/native/avx2/f32toa_subr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 51ef605

Please sign in to comment.