@@ -50,7 +50,7 @@ macro_rules! sequence {
50
50
51
51
macro_rules! read_num {
52
52
( $tok: ident, $num: ident, $then: expr) => {
53
- while let Some ( ch) = $tok. next_byte ( ) {
53
+ while let Some ( ch) = $tok. checked_next_byte ( ) {
54
54
match ch {
55
55
b'0' ... b'9' => {
56
56
let $num = ch - b'0' ;
@@ -213,22 +213,42 @@ impl<'a> Tokenizer<'a> {
213
213
214
214
fn read_number ( & mut self , first : u8 , is_negative : bool ) -> JsonResult < f64 > {
215
215
let mut num = ( first - b'0' ) as u64 ;
216
+ let mut digits = 0u8 ;
216
217
217
- read_num ! ( self , digit, num = num * 10 + digit as u64 ) ;
218
+ // Cap on how many iterations we do while reading to u64
219
+ // in order to avoid an overflow.
220
+ while digits < 18 {
221
+ digits += 1 ;
218
222
219
- match self . peek_byte ( ) {
220
- Some ( b'.' ) | Some ( b'e' ) | Some ( b'E' ) => { } ,
221
- _ => {
222
- return if is_negative {
223
- Ok ( -( num as f64 ) )
224
- } else {
225
- Ok ( num as f64 )
226
- } ;
223
+ if let Some ( ch) = self . next_byte ( ) {
224
+ match ch {
225
+ b'0' ... b'9' => {
226
+ num = num * 10 + ( ch - b'0' ) as u64 ;
227
+ } ,
228
+ b'.' | b'e' | b'E' => {
229
+ self . left_over = Some ( ch) ;
230
+ break ;
231
+ }
232
+ ch => {
233
+ self . left_over = Some ( ch) ;
234
+ return Ok (
235
+ if is_negative { -( num as f64 ) } else { num as f64 }
236
+ ) ;
237
+ }
238
+ }
239
+ } else {
240
+ return Ok (
241
+ if is_negative { -( num as f64 ) } else { num as f64 }
242
+ ) ;
227
243
}
228
244
}
229
245
230
246
let mut num = num as f64 ;
231
247
248
+ // Attempt to continue reading digits that would overflow
249
+ // u64 into freshly converted f64
250
+ read_num ! ( self , digit, num = num * 10.0 + digit as f64 ) ;
251
+
232
252
if let Some ( b'.' ) = self . peek_byte ( ) {
233
253
self . left_over = None ;
234
254
let mut precision = -1 ;
@@ -251,22 +271,14 @@ impl<'a> Tokenizer<'a> {
251
271
} ,
252
272
} ;
253
273
254
- while let Some ( ch) = self . checked_next_byte ( ) {
255
- match ch {
256
- b'0' ... b'9' => e = e * 10 + ( ch - b'0' ) as i32 ,
257
- ch => {
258
- self . left_over = Some ( ch) ;
259
- break ;
260
- }
261
- }
262
- }
274
+ read_num ! ( self , digit, e = e * 10 + digit as i32 ) ;
263
275
264
276
num *= 10f64 . powi ( e * sign) ;
265
277
} ,
266
278
byte => self . left_over = byte
267
279
}
268
280
269
- Ok ( if is_negative { num * - 1.0 } else { num } )
281
+ Ok ( if is_negative { -num } else { num } )
270
282
}
271
283
272
284
fn next ( & mut self ) -> JsonResult < Token > {
0 commit comments