From f087445eeec9a12c6e60f3f7aa19af4aa2a40a45 Mon Sep 17 00:00:00 2001 From: Yi Duan Date: Mon, 28 Feb 2022 20:14:38 +0800 Subject: [PATCH] fix: allow string value decoded as `json.Number` (#196) * fix: allow string value decoded as `json.Number` * test: move -race flag from Go1.15 since it reports "race: limit on 8128 simultaneously alive goroutines is exceeded, dying" * test: add benchmarks --- .github/workflows/push-check-go115.yml | 2 +- .github/workflows/push-check-go116.yml | 2 +- decoder/assembler_amd64_go116.go | 17 +++++++-- decoder/assembler_amd64_go117.go | 16 ++++++++- decoder/decoder_test.go | 4 +-- decoder/errors_test.go | 12 ------- decoder/norace_test.go | 12 +++++++ issue_test/issue195_test.go | 49 ++++++++++++++++++++++++++ 8 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 issue_test/issue195_test.go diff --git a/.github/workflows/push-check-go115.yml b/.github/workflows/push-check-go115.yml index cacde0a..d4502b8 100644 --- a/.github/workflows/push-check-go115.yml +++ b/.github/workflows/push-check-go115.yml @@ -21,4 +21,4 @@ jobs: ${{ runner.os }}-go- - name: Unit Test - run: GOMAXPROCS=4 go test -v -gcflags=-d=checkptr=0 -race -covermode=atomic -coverprofile=coverage.out ./... + run: GOMAXPROCS=4 go test -v -gcflags=-d=checkptr=0 -covermode=atomic -coverprofile=coverage.out ./... diff --git a/.github/workflows/push-check-go116.yml b/.github/workflows/push-check-go116.yml index 8f614c7..c35f082 100644 --- a/.github/workflows/push-check-go116.yml +++ b/.github/workflows/push-check-go116.yml @@ -21,4 +21,4 @@ jobs: ${{ runner.os }}-go- - name: Unit Test - run: GOMAXPROCS=4 go test -v -gcflags=-d=checkptr=0 -covermode=atomic -coverprofile=coverage.out ./... + run: GOMAXPROCS=4 go test -v -race -gcflags=-d=checkptr=0 -covermode=atomic -coverprofile=coverage.out ./... diff --git a/decoder/assembler_amd64_go116.go b/decoder/assembler_amd64_go116.go index 9dc5440..7ac7974 100644 --- a/decoder/assembler_amd64_go116.go +++ b/decoder/assembler_amd64_go116.go @@ -71,7 +71,7 @@ const ( _FP_args = 96 // 96 bytes to pass arguments and return values for this function _FP_fargs = 80 // 80 bytes for passing arguments to other Go functions _FP_saves = 40 // 40 bytes for saving the registers before CALL instructions - _FP_locals = 112 // 112 bytes for local variables + _FP_locals = 120 // 120 bytes for local variables ) const ( @@ -195,6 +195,8 @@ var ( _VAR_bs_LR = jit.Ptr(_SP, _FP_fargs + _FP_saves + 104) ) +var _VAR_fl = jit.Ptr(_SP, _FP_fargs + _FP_saves + 112) + type _Assembler struct { jit.BaseAssembler p _Program @@ -1163,6 +1165,12 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) { } func (self *_Assembler) _asm_OP_num(_ *_Instr) { + self.Emit("MOVQ", jit.Imm(0), _VAR_fl) + self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"')) + self.Sjmp("JNE", "_parse_number_{n}") + self.Emit("MOVQ", jit.Imm(1), _VAR_fl) + self.Emit("ADDQ", jit.Imm(1), _IC) + self.Link("_parse_number_{n}") self.parse_number() // PARSE NUMBER self.slice_from(_VAR_st_Ep, 0) // SLICE st.Ep, $0 self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv) @@ -1173,8 +1181,13 @@ func (self *_Assembler) _asm_OP_num(_ *_Instr) { self.Link("_num_write_{n}") self.Emit("MOVQ", _SI, jit.Ptr(_VP, 8)) // MOVQ SI, 8(VP) self.WriteRecNotAX(13, _DI, jit.Ptr(_VP, 0), false, false) + self.Emit("CMPQ", _VAR_fl, jit.Imm(1)) + self.Sjmp("JNE", "_num_end_{n}") + self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"')) + self.Sjmp("JNE", _LB_char_0_error) + self.Emit("ADDQ", jit.Imm(1), _IC) + self.Link("_num_end_{n}") } - func (self *_Assembler) _asm_OP_i8(_ *_Instr) { self.parse_signed() // PARSE int8 self.range_signed(_I_int8, _T_int8, math.MinInt8, math.MaxInt8) // RANGE int8 diff --git a/decoder/assembler_amd64_go117.go b/decoder/assembler_amd64_go117.go index af213b5..3d254bf 100644 --- a/decoder/assembler_amd64_go117.go +++ b/decoder/assembler_amd64_go117.go @@ -71,7 +71,7 @@ const ( _FP_args = 72 // 72 bytes to pass and spill register arguements _FP_fargs = 80 // 80 bytes for passing arguments to other Go functions _FP_saves = 48 // 48 bytes for saving the registers before CALL instructions - _FP_locals = 112 // 112 bytes for local variables + _FP_locals = 120 // 112 bytes for local variables ) const ( @@ -190,6 +190,8 @@ var ( _VAR_bs_LR = jit.Ptr(_SP, _FP_fargs + _FP_saves + 104) ) +var _VAR_fl = jit.Ptr(_SP, _FP_fargs + _FP_saves + 112) + type _Assembler struct { jit.BaseAssembler p _Program @@ -1160,6 +1162,12 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) { } func (self *_Assembler) _asm_OP_num(_ *_Instr) { + self.Emit("MOVQ", jit.Imm(0), _VAR_fl) + self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"')) + self.Sjmp("JNE", "_parse_number_{n}") + self.Emit("MOVQ", jit.Imm(1), _VAR_fl) + self.Emit("ADDQ", jit.Imm(1), _IC) + self.Link("_parse_number_{n}") self.parse_number() // PARSE NUMBER self.slice_from(_VAR_st_Ep, 0) // SLICE st.Ep, $0 self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv) @@ -1170,6 +1178,12 @@ func (self *_Assembler) _asm_OP_num(_ *_Instr) { self.Link("_num_write_{n}") self.Emit("MOVQ", _SI, jit.Ptr(_VP, 8)) // MOVQ SI, 8(VP) self.WriteRecNotAX(13, _DI, jit.Ptr(_VP, 0), false, false) + self.Emit("CMPQ", _VAR_fl, jit.Imm(1)) + self.Sjmp("JNE", "_num_end_{n}") + self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"')) + self.Sjmp("JNE", _LB_char_0_error) + self.Emit("ADDQ", jit.Imm(1), _IC) + self.Link("_num_end_{n}") } func (self *_Assembler) _asm_OP_i8(_ *_Instr) { diff --git a/decoder/decoder_test.go b/decoder/decoder_test.go index df7eebe..f8f080a 100644 --- a/decoder/decoder_test.go +++ b/decoder/decoder_test.go @@ -34,7 +34,7 @@ import ( func TestMain(m *testing.M) { go func () { - if !debugAsyncGC { + if debugAsyncGC { return } println("Begin GC looping...") @@ -49,7 +49,7 @@ func TestMain(m *testing.M) { } func TestGC(t *testing.T) { - if debugSyncGC { + if !debugSyncGC { return } var w interface{} diff --git a/decoder/errors_test.go b/decoder/errors_test.go index 59f361e..149b155 100644 --- a/decoder/errors_test.go +++ b/decoder/errors_test.go @@ -56,16 +56,4 @@ func TestErrors_ShortDescription(t *testing.T) { func TestErrors_EmptyDescription(t *testing.T) { println(make_err("", 0).Description()) -} - -func TestDecoderErrorStackOverflower(t *testing.T) { - src := `{"a":[]}` - N := _MaxStack - for i:=0; i