commit 76ee8ffba42b86b46b71bf32ac0d15ccd5f871f3
parent 0298226a77a70f5ad3ac2b0f45a6a9dbe2837597
Author: francoispqt <francois@parquet.ninja>
Date: Mon, 21 May 2018 08:59:11 +0800
add fuzz testing and start fixing crashers found
Diffstat:
4 files changed, 129 insertions(+), 14 deletions(-)
diff --git a/decode_number.go b/decode_number.go
@@ -85,7 +85,7 @@ func (dec *Decoder) getExponent() int64 {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] { // is positive
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- end = dec.cursor
+ end = dec.cursor + 1
case '-':
dec.cursor++
return -dec.getExponent()
@@ -99,8 +99,12 @@ func (dec *Decoder) getExponent() int64 {
dec.raiseInvalidJSONErr(dec.cursor)
return 0
}
- return dec.atoi64(start, end)
+ return dec.atoi64(start, end-1)
}
}
- return dec.atoi64(start, end)
+ if start == end {
+ dec.raiseInvalidJSONErr(dec.cursor)
+ return 0
+ }
+ return dec.atoi64(start, end-1)
}
diff --git a/decode_number_int.go b/decode_number_int.go
@@ -21,7 +21,7 @@ func (dec *Decoder) decodeInt(v *int) error {
continue
// we don't look for 0 as leading zeros are invalid per RFC
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- val, err := dec.getInt64(c)
+ val, err := dec.getInt64()
if err != nil {
return err
}
@@ -29,7 +29,7 @@ func (dec *Decoder) decodeInt(v *int) error {
return nil
case '-':
dec.cursor = dec.cursor + 1
- val, err := dec.getInt64(dec.data[dec.cursor])
+ val, err := dec.getInt64()
if err != nil {
return err
}
@@ -151,6 +151,9 @@ func (dec *Decoder) getInt16(b byte) (int16, error) {
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
// we have the floating value, now multiply by the exponent
exp := dec.getExponent()
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
val := floatVal * float64(pow10uint64[exp+1])
return int16(val), nil
case ' ', '\t', '\n', ',', ']', '}':
@@ -194,6 +197,9 @@ func (dec *Decoder) getInt16WithExp(init int16, cursor int) (int16, error) {
uintv := uint16(digits[dec.data[cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int16(pow10uint64[exp+1])), nil
}
@@ -202,6 +208,9 @@ func (dec *Decoder) getInt16WithExp(init int16, cursor int) (int16, error) {
return 0, InvalidJSONError(fmt.Sprintf(invalidJSONCharErrorMsg, dec.data[dec.cursor], dec.cursor))
}
}
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int16(pow10uint64[exp+1])), nil
}
@@ -303,6 +312,9 @@ func (dec *Decoder) getInt8(b byte) (int8, error) {
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
// we have the floating value, now multiply by the exponent
exp := dec.getExponent()
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
val := floatVal * float64(pow10uint64[exp+1])
return int8(val), nil
case ' ', '\t', '\n', ',', ']', '}':
@@ -310,7 +322,7 @@ func (dec *Decoder) getInt8(b byte) (int8, error) {
return dec.atoi8(start, end), nil
default:
dec.cursor = j
- return 0, InvalidJSONError(fmt.Sprintf(invalidJSONCharErrorMsg, dec.data[dec.cursor], dec.cursor))
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return dec.atoi8(start, end), nil
@@ -346,14 +358,20 @@ func (dec *Decoder) getInt8WithExp(init int8, cursor int) (int8, error) {
uintv := uint8(digits[dec.data[cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int8(pow10uint64[exp+1])), nil
}
return init * int8(pow10uint64[exp+1]), nil
default:
- return 0, InvalidJSONError(fmt.Sprintf(invalidJSONCharErrorMsg, dec.data[dec.cursor], dec.cursor))
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int8(pow10uint64[exp+1])), nil
}
@@ -461,7 +479,7 @@ func (dec *Decoder) getInt32(b byte) (int32, error) {
return dec.atoi32(start, end), nil
default:
dec.cursor = j
- return 0, InvalidJSONError(fmt.Sprintf(invalidJSONCharErrorMsg, dec.data[dec.cursor], dec.cursor))
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return dec.atoi32(start, end), nil
@@ -497,14 +515,20 @@ func (dec *Decoder) getInt32WithExp(init int32, cursor int) (int32, error) {
uintv := uint32(digits[dec.data[cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int32(pow10uint64[exp+1])), nil
}
return init * int32(pow10uint64[exp+1]), nil
default:
- return 0, InvalidJSONError(fmt.Sprintf(invalidJSONCharErrorMsg, dec.data[dec.cursor], dec.cursor))
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int32(pow10uint64[exp+1])), nil
}
@@ -533,7 +557,7 @@ func (dec *Decoder) decodeInt64(v *int64) error {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- val, err := dec.getInt64(c)
+ val, err := dec.getInt64()
if err != nil {
return err
}
@@ -541,7 +565,7 @@ func (dec *Decoder) decodeInt64(v *int64) error {
return nil
case '-':
dec.cursor = dec.cursor + 1
- val, err := dec.getInt64(dec.data[dec.cursor])
+ val, err := dec.getInt64()
if err != nil {
return err
}
@@ -566,7 +590,7 @@ func (dec *Decoder) decodeInt64(v *int64) error {
return dec.raiseInvalidJSONErr(dec.cursor)
}
-func (dec *Decoder) getInt64(b byte) (int64, error) {
+func (dec *Decoder) getInt64() (int64, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
@@ -609,6 +633,9 @@ func (dec *Decoder) getInt64(b byte) (int64, error) {
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
// we have the floating value, now multiply by the exponent
exp := dec.getExponent()
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
val := floatVal * float64(pow10uint64[exp+1])
return int64(val), nil
case ' ', '\t', '\n', ',', ']', '}':
@@ -616,7 +643,7 @@ func (dec *Decoder) getInt64(b byte) (int64, error) {
return dec.atoi64(start, end), nil
default:
dec.cursor = j
- return 0, InvalidJSONError(fmt.Sprintf(invalidJSONCharErrorMsg, dec.data[dec.cursor], dec.cursor))
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return dec.atoi64(start, end), nil
@@ -649,14 +676,20 @@ func (dec *Decoder) getInt64WithExp(init int64, cursor int) (int64, error) {
uintv := uint64(digits[dec.data[cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int64(pow10uint64[exp+1])), nil
}
return init * int64(pow10uint64[exp+1]), nil
default:
- return 0, InvalidJSONError(fmt.Sprintf(invalidJSONCharErrorMsg, dec.data[dec.cursor], dec.cursor))
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
+ if int(exp+1) >= len(pow10uint64) {
+ return 0, dec.raiseInvalidJSONErr(dec.cursor)
+ }
if sign == -1 {
return init * (1 / int64(pow10uint64[exp+1])), nil
}
diff --git a/decode_number_int_test.go b/decode_number_int_test.go
@@ -189,6 +189,20 @@ func TestDecoderInt(t *testing.T) {
errType: InvalidJSONError(""),
},
{
+ name: "error3",
+ json: "0.E----",
+ expectedResult: 0,
+ err: true,
+ errType: InvalidJSONError(""),
+ },
+ {
+ name: "error3",
+ json: "0E40",
+ expectedResult: 0,
+ err: true,
+ errType: InvalidJSONError(""),
+ },
+ {
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
@@ -383,6 +397,13 @@ func TestDecoderInt64(t *testing.T) {
expectedResult: 0,
},
{
+ name: "error3",
+ json: "0E40",
+ expectedResult: 0,
+ err: true,
+ errType: InvalidJSONError(""),
+ },
+ {
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
@@ -661,6 +682,13 @@ func TestDecoderInt32(t *testing.T) {
err: true,
},
{
+ name: "error3",
+ json: "0E40",
+ expectedResult: 0,
+ err: true,
+ errType: InvalidJSONError(""),
+ },
+ {
name: "basic-float",
json: "8.32 ",
expectedResult: 8,
@@ -947,6 +975,13 @@ func TestDecoderInt16(t *testing.T) {
err: true,
},
{
+ name: "error3",
+ json: "0E40",
+ expectedResult: 0,
+ err: true,
+ errType: InvalidJSONError(""),
+ },
+ {
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
@@ -1172,6 +1207,13 @@ func TestDecoderInt8(t *testing.T) {
expectedResult: -30,
},
{
+ name: "error3",
+ json: "0E40",
+ expectedResult: 0,
+ err: true,
+ errType: InvalidJSONError(""),
+ },
+ {
name: "basic-exponent-negative-positive-exp4",
json: "-8e+001",
expectedResult: -80,
diff --git a/examples/fuzz/main.go b/examples/fuzz/main.go
@@ -0,0 +1,36 @@
+package fuzz
+
+import (
+ "github.com/francoispqt/gojay"
+)
+
+type user struct {
+ id int
+ name string
+ email string
+}
+
+// implement gojay.UnmarshalerJSONObject
+func (u *user) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
+ switch key {
+ case "id":
+ return dec.Int(&u.id)
+ case "name":
+ return dec.String(&u.name)
+ case "email":
+ return dec.String(&u.email)
+ }
+ return nil
+}
+func (u *user) NKeys() int {
+ return 3
+}
+
+func Fuzz(input []byte) int {
+ u := &user{}
+ err := gojay.UnmarshalJSONObject(input, u)
+ if err != nil {
+ return 0
+ }
+ return 1
+}