Skip to content

Commit efc4a69

Browse files
authored
Merge pull request #28 from francoispqt/update/fuzz-crashers-fix
Fix cases where malformed integers could cause a panic
2 parents 0298226 + a110d70 commit efc4a69

10 files changed

+673
-81
lines changed

decode_number.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func (dec *Decoder) getExponent() int64 {
8585
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
8686
switch dec.data[dec.cursor] { // is positive
8787
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
88-
end = dec.cursor
88+
end = dec.cursor + 1
8989
case '-':
9090
dec.cursor++
9191
return -dec.getExponent()
@@ -99,8 +99,12 @@ func (dec *Decoder) getExponent() int64 {
9999
dec.raiseInvalidJSONErr(dec.cursor)
100100
return 0
101101
}
102-
return dec.atoi64(start, end)
102+
return dec.atoi64(start, end-1)
103103
}
104104
}
105-
return dec.atoi64(start, end)
105+
if start == end {
106+
dec.raiseInvalidJSONErr(dec.cursor)
107+
return 0
108+
}
109+
return dec.atoi64(start, end-1)
106110
}

decode_number_float.go

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ func (dec *Decoder) decodeFloat64(v *float64) error {
1515
case ' ', '\n', '\t', '\r', ',':
1616
continue
1717
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
18-
val, err := dec.getFloat(c)
18+
val, err := dec.getFloat()
1919
if err != nil {
2020
return err
2121
}
2222
*v = val
2323
return nil
2424
case '-':
2525
dec.cursor = dec.cursor + 1
26-
val, err := dec.getFloat(c)
26+
val, err := dec.getFloatNegative()
2727
if err != nil {
2828
return err
2929
}
@@ -48,7 +48,20 @@ func (dec *Decoder) decodeFloat64(v *float64) error {
4848
return dec.raiseInvalidJSONErr(dec.cursor)
4949
}
5050

51-
func (dec *Decoder) getFloat(b byte) (float64, error) {
51+
func (dec *Decoder) getFloatNegative() (float64, error) {
52+
// look for following numbers
53+
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
54+
switch dec.data[dec.cursor] {
55+
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
56+
return dec.getFloat()
57+
default:
58+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
59+
}
60+
}
61+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
62+
}
63+
64+
func (dec *Decoder) getFloat() (float64, error) {
5265
var end = dec.cursor
5366
var start = dec.cursor
5467
// look for following numbers
@@ -73,9 +86,16 @@ func (dec *Decoder) getFloat(b byte) (float64, error) {
7386
} else if c == 'e' || c == 'E' {
7487
afterDecimal := dec.atoi64(start, end)
7588
dec.cursor = i + 1
76-
pow := pow10uint64[end-start+2]
89+
expI := end - start + 2
90+
if expI >= len(pow10uint64) || expI < 0 {
91+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
92+
}
93+
pow := pow10uint64[expI]
7794
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
7895
exp := dec.getExponent()
96+
if +exp+1 >= int64(len(pow10uint64)) {
97+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
98+
}
7999
// if exponent is negative
80100
if exp < 0 {
81101
return float64(floatVal) * (1 / float64(pow10uint64[exp*-1+1])), nil
@@ -88,14 +108,21 @@ func (dec *Decoder) getFloat(b byte) (float64, error) {
88108
// then we add both integers
89109
// then we divide the number by the power found
90110
afterDecimal := dec.atoi64(start, end)
91-
pow := pow10uint64[end-start+2]
111+
expI := end - start + 2
112+
if expI >= len(pow10uint64) || expI < 0 {
113+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
114+
}
115+
pow := pow10uint64[expI]
92116
return float64(beforeDecimal+afterDecimal) / float64(pow), nil
93117
case 'e', 'E':
94-
dec.cursor = dec.cursor + 2
118+
dec.cursor = j + 1
95119
// we get part before decimal as integer
96120
beforeDecimal := uint64(dec.atoi64(start, end))
97121
// get exponent
98122
exp := dec.getExponent()
123+
if +exp+1 >= int64(len(pow10uint64)) {
124+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
125+
}
99126
// if exponent is negative
100127
if exp < 0 {
101128
return float64(beforeDecimal) * (1 / float64(pow10uint64[exp*-1+1])), nil
@@ -126,15 +153,15 @@ func (dec *Decoder) decodeFloat32(v *float32) error {
126153
case ' ', '\n', '\t', '\r', ',':
127154
continue
128155
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
129-
val, err := dec.getFloat32(c)
156+
val, err := dec.getFloat32()
130157
if err != nil {
131158
return err
132159
}
133160
*v = val
134161
return nil
135162
case '-':
136163
dec.cursor = dec.cursor + 1
137-
val, err := dec.getFloat32(c)
164+
val, err := dec.getFloat32Negative()
138165
if err != nil {
139166
return err
140167
}
@@ -159,7 +186,20 @@ func (dec *Decoder) decodeFloat32(v *float32) error {
159186
return dec.raiseInvalidJSONErr(dec.cursor)
160187
}
161188

162-
func (dec *Decoder) getFloat32(b byte) (float32, error) {
189+
func (dec *Decoder) getFloat32Negative() (float32, error) {
190+
// look for following numbers
191+
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
192+
switch dec.data[dec.cursor] {
193+
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
194+
return dec.getFloat32()
195+
default:
196+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
197+
}
198+
}
199+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
200+
}
201+
202+
func (dec *Decoder) getFloat32() (float32, error) {
163203
var end = dec.cursor
164204
var start = dec.cursor
165205
// look for following numbers
@@ -184,9 +224,16 @@ func (dec *Decoder) getFloat32(b byte) (float32, error) {
184224
} else if c == 'e' || c == 'E' {
185225
afterDecimal := dec.atoi32(start, end)
186226
dec.cursor = i + 1
187-
pow := pow10uint64[end-start+2]
227+
expI := end - start + 2
228+
if expI >= len(pow10uint64) || expI < 0 {
229+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
230+
}
231+
pow := pow10uint64[expI]
188232
floatVal := float32(beforeDecimal+afterDecimal) / float32(pow)
189233
exp := dec.getExponent()
234+
if +exp+1 >= int64(len(pow10uint64)) {
235+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
236+
}
190237
// if exponent is negative
191238
if exp < 0 {
192239
return float32(floatVal) * (1 / float32(pow10uint64[exp*-1+1])), nil
@@ -199,14 +246,21 @@ func (dec *Decoder) getFloat32(b byte) (float32, error) {
199246
// then we add both integers
200247
// then we divide the number by the power found
201248
afterDecimal := dec.atoi32(start, end)
202-
pow := pow10uint64[end-start+2]
249+
expI := end - start + 2
250+
if expI >= len(pow10uint64) || expI < 0 {
251+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
252+
}
253+
pow := pow10uint64[expI]
203254
return float32(beforeDecimal+afterDecimal) / float32(pow), nil
204255
case 'e', 'E':
205-
dec.cursor = dec.cursor + 2
256+
dec.cursor = j + 1
206257
// we get part before decimal as integer
207258
beforeDecimal := uint32(dec.atoi32(start, end))
208259
// get exponent
209260
exp := dec.getExponent()
261+
if +exp+1 >= int64(len(pow10uint64)) {
262+
return 0, dec.raiseInvalidJSONErr(dec.cursor)
263+
}
210264
// if exponent is negative
211265
if exp < 0 {
212266
return float32(beforeDecimal) * (1 / float32(pow10uint64[exp*-1+1])), nil

decode_number_float_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ func TestDecoderFloat64(t *testing.T) {
4545
err: true,
4646
errType: InvalidJSONError(""),
4747
},
48+
{
49+
name: "basic-negative-err",
50+
json: "-",
51+
expectedResult: 0,
52+
err: true,
53+
errType: InvalidJSONError(""),
54+
},
55+
{
56+
name: "basic-negative-err",
57+
json: "-q",
58+
expectedResult: 0,
59+
err: true,
60+
errType: InvalidJSONError(""),
61+
},
4862
{
4963
name: "basic-null-err",
5064
json: "trua",
@@ -132,6 +146,30 @@ func TestDecoderFloat64(t *testing.T) {
132146
json: "-7.8876e002",
133147
expectedResult: -788.76,
134148
},
149+
{
150+
name: "basic-exp-too-big",
151+
json: "1e10000000000 ",
152+
expectedResult: 0,
153+
err: true,
154+
},
155+
{
156+
name: "basic-exp-too-big",
157+
json: "1.002e10000000000 ",
158+
expectedResult: 0,
159+
err: true,
160+
},
161+
{
162+
name: "basic-exp-too-big",
163+
json: "1.00232492420002423545849009",
164+
expectedResult: 0,
165+
err: true,
166+
},
167+
{
168+
name: "basic-exp-too-big",
169+
json: "1.00232492420002423545849009e10000000000 ",
170+
expectedResult: 0,
171+
err: true,
172+
},
135173
{
136174
name: "error",
137175
json: "83zez4",
@@ -255,6 +293,20 @@ func TestDecoderFloat32(t *testing.T) {
255293
err: true,
256294
errType: InvalidJSONError(""),
257295
},
296+
{
297+
name: "basic-negative-err",
298+
json: "-",
299+
expectedResult: 0,
300+
err: true,
301+
errType: InvalidJSONError(""),
302+
},
303+
{
304+
name: "basic-negative-err",
305+
json: "-q",
306+
expectedResult: 0,
307+
err: true,
308+
errType: InvalidJSONError(""),
309+
},
258310
{
259311
name: "basic-exponent-positive-positive-exp4",
260312
json: "8e+005",
@@ -305,6 +357,36 @@ func TestDecoderFloat32(t *testing.T) {
305357
json: "-8.2e-005",
306358
expectedResult: -0.000082,
307359
},
360+
{
361+
name: "basic-exp-too-big",
362+
json: "1e10000000000 ",
363+
expectedResult: 0,
364+
err: true,
365+
},
366+
{
367+
name: "basic-exp-too-big",
368+
json: "1.0023249242000242e10000000000 ",
369+
expectedResult: 0,
370+
err: true,
371+
},
372+
{
373+
name: "basic-exp-too-big",
374+
json: "1.002e10000000000 ",
375+
expectedResult: 0,
376+
err: true,
377+
},
378+
{
379+
name: "basic-exp-too-big",
380+
json: "1.00232492420002423545849009",
381+
expectedResult: 0,
382+
err: true,
383+
},
384+
{
385+
name: "basic-exp-too-big",
386+
json: "1.00232492420002423545849009e10000000000 ",
387+
expectedResult: 0,
388+
err: true,
389+
},
308390
{
309391
name: "basic-float",
310392
json: "2.4595",

0 commit comments

Comments
 (0)