From f705934fbfdd4bbed9362ba476037fcaad8aa4a1 Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Tue, 18 Jul 2017 23:48:40 +0800 Subject: [PATCH] #138 fix - without following digits; fix 1.e1 --- feature_iter_float.go | 49 +++++++++++--------- feature_iter_skip_strict.go | 3 ++ jsoniter_invalid_test.go | 89 ++++++++++++------------------------- 3 files changed, 61 insertions(+), 80 deletions(-) diff --git a/feature_iter_float.go b/feature_iter_float.go index a6b99bd..86f4599 100644 --- a/feature_iter_float.go +++ b/feature_iter_float.go @@ -4,6 +4,7 @@ import ( "io" "math/big" "strconv" + "strings" "unsafe" ) @@ -192,16 +193,9 @@ func (iter *Iterator) readFloat32SlowPath() (ret float32) { if iter.Error != nil && iter.Error != io.EOF { return } - if len(str) == 0 { - iter.ReportError("readFloat32SlowPath", "empty number") - return - } - if str[0] == '-' { - iter.ReportError("readFloat32SlowPath", "-- is not valid") - return - } - if str[len(str)-1] == '.' { - iter.ReportError("readFloat32SlowPath", "dot can not be last character") + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat32SlowPath", errMsg) return } val, err := strconv.ParseFloat(str, 32) @@ -311,16 +305,9 @@ func (iter *Iterator) readFloat64SlowPath() (ret float64) { if iter.Error != nil && iter.Error != io.EOF { return } - if len(str) == 0 { - iter.ReportError("readFloat64SlowPath", "empty number") - return - } - if str[0] == '-' { - iter.ReportError("readFloat64SlowPath", "-- is not valid") - return - } - if str[len(str)-1] == '.' { - iter.ReportError("readFloat64SlowPath", "dot can not be last character") + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat64SlowPath", errMsg) return } val, err := strconv.ParseFloat(str, 64) @@ -330,3 +317,25 @@ func (iter *Iterator) readFloat64SlowPath() (ret float64) { } return val } + +func validateFloat(str string) string { + // strconv.ParseFloat is not validating `1.` or `1.e1` + if len(str) == 0 { + return "empty number" + } + if str[0] == '-' { + return "-- is not valid" + } + dotPos := strings.IndexByte(str, '.') + if dotPos != -1 { + if dotPos == len(str)-1 { + return "dot can not be last character" + } + switch str[dotPos+1] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + return "missing digit after dot" + } + } + return "" +} diff --git a/feature_iter_skip_strict.go b/feature_iter_skip_strict.go index c282960..d267638 100644 --- a/feature_iter_skip_strict.go +++ b/feature_iter_skip_strict.go @@ -36,6 +36,9 @@ func (iter *Iterator) trySkipNumber() bool { default: switch c { case ',', ']', '}', ' ', '\t', '\n', '\r': + if iter.head == i { + return false // if - without following digits + } iter.head = i return true // must be valid } diff --git a/jsoniter_invalid_test.go b/jsoniter_invalid_test.go index a8d4a3c..7d54ca4 100644 --- a/jsoniter_invalid_test.go +++ b/jsoniter_invalid_test.go @@ -68,64 +68,33 @@ func Test_invalid_array_input(t *testing.T) { should.NotNil(Unmarshal(input, &obj)) } -func Test_double_negative(t *testing.T) { - should := require.New(t) - var v interface{} - should.NotNil(json.Unmarshal([]byte(`--2`), &v)) - var vFloat64 float64 - should.NotNil(UnmarshalFromString(`--2`, &vFloat64)) - var vFloat32 float32 - should.NotNil(UnmarshalFromString(`--2`, &vFloat32)) - var vInt int - should.NotNil(UnmarshalFromString(`--2`, &vInt)) - iter := ParseString(ConfigDefault, `--2`) - iter.Skip() - should.NotEqual(io.EOF, iter.Error) - should.NotNil(iter.Error) -} - -func Test_leading_zero(t *testing.T) { - should := require.New(t) - var v interface{} - should.NotNil(json.Unmarshal([]byte(`01`), &v)) - var vFloat64 float64 - should.NotNil(UnmarshalFromString(`01`, &vFloat64)) - var vFloat32 float32 - should.NotNil(UnmarshalFromString(`01`, &vFloat32)) - var vInt int - should.NotNil(UnmarshalFromString(`01`, &vInt)) - iter := ParseString(ConfigDefault, `01,`) - iter.Skip() - should.NotEqual(io.EOF, iter.Error) - should.NotNil(iter.Error) -} - -func Test_empty_as_number(t *testing.T) { - should := require.New(t) - iter := ParseString(ConfigDefault, `,`) - iter.ReadFloat64() - should.NotEqual(io.EOF, iter.Error) - should.NotNil(iter.Error) - iter = ParseString(ConfigDefault, `,`) - iter.ReadFloat32() - should.NotEqual(io.EOF, iter.Error) - should.NotNil(iter.Error) -} - -func Test_missing_digit_after_dot(t *testing.T) { - should := require.New(t) - iter := ParseString(ConfigDefault, `1.,`) - iter.Skip() - should.NotEqual(io.EOF, iter.Error) - should.NotNil(iter.Error) - v := float64(0) - should.NotNil(json.Unmarshal([]byte(`1.`), &v)) - iter = ParseString(ConfigDefault, `1.`) - iter.ReadFloat64() - should.NotEqual(io.EOF, iter.Error) - should.NotNil(iter.Error) - iter = ParseString(ConfigDefault, `1.`) - iter.ReadFloat32() - should.NotEqual(io.EOF, iter.Error) - should.NotNil(iter.Error) +func Test_invalid_float(t *testing.T) { + inputs := []string{ + `1.e1`, // dot without following digit + `1.`, // dot can not be the last char + ``, // empty number + `01`, // extra leading zero + `-`, // negative without digit + `--`, // double negative + `--2`, // double negative + } + for _, input := range inputs { + t.Run(input, func(t *testing.T) { + should := require.New(t) + iter := ParseString(ConfigDefault, input+",") + iter.Skip() + should.NotEqual(io.EOF, iter.Error) + should.NotNil(iter.Error) + v := float64(0) + should.NotNil(json.Unmarshal([]byte(input), &v)) + iter = ParseString(ConfigDefault, input+",") + iter.ReadFloat64() + should.NotEqual(io.EOF, iter.Error) + should.NotNil(iter.Error) + iter = ParseString(ConfigDefault, input+",") + iter.ReadFloat32() + should.NotEqual(io.EOF, iter.Error) + should.NotNil(iter.Error) + }) + } }