Skip to content

Commit

Permalink
fix: add nil pointer check (#224)
Browse files Browse the repository at this point in the history
* fix: add nil pointer check

* panicNilPointerOfNonEmptyString
  • Loading branch information
AsterDY authored May 19, 2022
1 parent d923a03 commit 5086cb2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 13 deletions.
21 changes: 20 additions & 1 deletion encoder/assembler_amd64_go116.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const (
_LB_error_too_deep = "_error_too_deep"
_LB_error_invalid_number = "_error_invalid_number"
_LB_error_nan_or_infinite = "_error_nan_or_infinite"
_LB_panic = "_panic"
)

var (
Expand Down Expand Up @@ -273,6 +274,7 @@ func (self *_Assembler) builtins() {
self.error_too_deep()
self.error_invalid_number()
self.error_nan_or_infinite()
self.go_panic()
}

func (self *_Assembler) epilogue() {
Expand Down Expand Up @@ -625,12 +627,24 @@ func (self *_Assembler) error_nan_or_infinite() {

var (
_F_quote = jit.Imm(int64(native.S_quote))
_F_panic = jit.Func(goPanic)
)

func (self *_Assembler) go_panic() {
self.Link(_LB_panic)
self.Emit("MOVQ", _SP_p, jit.Ptr(_SP, 8))
self.call_go(_F_panic)
}

func (self *_Assembler) encode_string(doubleQuote bool) {
self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _AX) // MOVQ 8(SP.p), AX
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
self.Sjmp("JZ" , "_str_empty_{n}") // JZ _str_empty_{n}
self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0))
self.Sjmp("JNE" , "_str_next_{n}")
self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), jit.Ptr(_SP, 0))
self.Sjmp("JMP", _LB_panic)
self.Link("_str_next_{n}")

/* openning quote, check for double quote */
if !doubleQuote {
Expand Down Expand Up @@ -865,10 +879,15 @@ func (self *_Assembler) _asm_OP_quote(_ *_Instr) {
}

func (self *_Assembler) _asm_OP_number(_ *_Instr) {
self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX
self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _CX) // MOVQ (SP.p), CX
self.Emit("TESTQ", _CX, _CX) // TESTQ CX, CX
self.Sjmp("JZ" , "_empty_{n}") // JZ _empty_{n}
self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
self.Sjmp("JNZ" , "_number_next_{n}")
self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), jit.Ptr(_SP, 0))
self.Sjmp("JMP", _LB_panic)
self.Link("_number_next_{n}")
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
self.call_go(_F_isValidNumber) // CALL_GO isValidNumber
Expand Down
23 changes: 21 additions & 2 deletions encoder/assembler_amd64_go117.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ const (
_LB_error_too_deep = "_error_too_deep"
_LB_error_invalid_number = "_error_invalid_number"
_LB_error_nan_or_infinite = "_error_nan_or_infinite"
_LB_panic = "_panic"
)

var (
Expand Down Expand Up @@ -277,6 +278,7 @@ func (self *_Assembler) builtins() {
self.error_too_deep()
self.error_invalid_number()
self.error_nan_or_infinite()
self.go_panic()
}

func (self *_Assembler) epilogue() {
Expand Down Expand Up @@ -636,12 +638,24 @@ func (self *_Assembler) error_nan_or_infinite() {

var (
_F_quote = jit.Imm(int64(native.S_quote))
_F_panic = jit.Func(goPanic)
)

func (self *_Assembler) encode_string(doubleQuote bool) {
func (self *_Assembler) go_panic() {
self.Link(_LB_panic)
self.Emit("MOVQ", _SP_p, _BX)
self.call_go(_F_panic)
}

func (self *_Assembler) encode_string(doubleQuote bool) {
self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _AX) // MOVQ 8(SP.p), AX
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
self.Sjmp("JZ" , "_str_empty_{n}") // JZ _str_empty_{n}
self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0))
self.Sjmp("JNE" , "_str_next_{n}")
self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), _AX)
self.Sjmp("JMP", _LB_panic)
self.Link("_str_next_{n}")

/* openning quote, check for double quote */
if !doubleQuote {
Expand Down Expand Up @@ -877,10 +891,15 @@ func (self *_Assembler) _asm_OP_quote(_ *_Instr) {
}

func (self *_Assembler) _asm_OP_number(_ *_Instr) {
self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX
self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _BX) // MOVQ (SP.p), BX
self.Emit("TESTQ", _BX, _BX) // TESTQ BX, BX
self.Sjmp("JZ" , "_empty_{n}")
self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
self.Sjmp("JNZ" , "_number_next_{n}")
self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), _AX)
self.Sjmp("JMP", _LB_panic)
self.Link("_number_next_{n}")
self.call_go(_F_isValidNumber) // CALL_GO isValidNumber
self.Emit("CMPB" , _AX, jit.Imm(0)) // CMPB AX, $0
self.Sjmp("JE" , _LB_error_invalid_number) // JE _error_invalid_number
Expand Down
55 changes: 45 additions & 10 deletions encoder/assembler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
package encoder

import (
`encoding/hex`
`encoding/json`
`math`
`reflect`
`runtime`
`testing`
`unsafe`
"encoding/hex"
"encoding/json"
"math"
"reflect"
"runtime"
"strings"
"testing"
"unsafe"

`github.com/bytedance/sonic/internal/rt`
`github.com/davecgh/go-spew/spew`
`github.com/stretchr/testify/assert`
"github.com/bytedance/sonic/internal/rt"
"github.com/davecgh/go-spew/spew"
"github.com/stretchr/testify/assert"
)

func TestAssembler_CompileAndLoad(t *testing.T) {
Expand Down Expand Up @@ -375,3 +376,37 @@ func TestAssembler_TwitterJSON_Structure(t *testing.T) {
println(string(m))
runtime.KeepAlive(s)
}

func TestScratchedString(t *testing.T) {
fatal := *(*string)(unsafe.Pointer(&rt.GoString{nil, 1}))
defer func(){
if v := recover(); v == nil {
t.Fatal()
} else if s, ok := v.(string); !ok {
t.Fatal(v)
}else{
if !strings.Contains(s, "has nil pointer while its length is not zero") {
t.Fatal(s)
}
}
}()
_, _ = Encode(fatal, 0)
t.Fatal()
}

func TestScratchedNumber(t *testing.T) {
fatal := *(*json.Number)(unsafe.Pointer(&rt.GoString{nil, 1}))
defer func(){
if v := recover(); v == nil {
t.Fatal()
} else if s, ok := v.(string); !ok {
t.Fatal(v)
}else{
if !strings.Contains(s, "has nil pointer while its length is not zero") {
t.Fatal(s)
}
}
}()
_, _ = Encode(fatal, 0)
t.Fatal()
}
16 changes: 16 additions & 0 deletions encoder/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import (
`fmt`
`reflect`
`strconv`
`unsafe`

`github.com/bytedance/sonic/internal/rt`
)

var _ERR_too_deep = &json.UnsupportedValueError {
Expand All @@ -47,3 +50,16 @@ func error_number(number json.Number) error {
func error_marshaler(ret []byte, pos int) error {
return fmt.Errorf("invalid Marshaler output json syntax at %d: %q", pos, ret)
}

const (
panicNilPointerOfNonEmptyString int = 1 + iota
)

func goPanic(code int, val unsafe.Pointer) {
switch(code){
case panicNilPointerOfNonEmptyString:
panic(fmt.Sprintf("val: %#v has nil pointer while its length is not zero!", (*rt.GoString)(val)))
default:
panic("encoder error!")
}
}

0 comments on commit 5086cb2

Please sign in to comment.