Repository: serde-rs/json (Rust)

Issue:
Malformed number causes panic in de.rs
The following test case demonstrates the problem. This could be used for DOSing Rust web apps.
 ```rust
extern crate serde_json;

#[test]
fn parse_json() {
    let f: Result<f64, _> = serde_json::from_str("3.5E-2147483647");
}
```

```
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:211
   3: std::panicking::default_hook
             at libstd/panicking.rs:227
   4: std::panicking::rust_panic_with_hook
             at libstd/panicking.rs:475
   5: std::panicking::continue_panic_fmt
             at libstd/panicking.rs:390
   6: rust_begin_unwind
             at libstd/panicking.rs:325
   7: core::panicking::panic_fmt
             at libcore/panicking.rs:77
   8: core::panicking::panic
             at libcore/panicking.rs:52
   9: core::num::<impl i32>::abs
             at /checkout/src/libcore/num/mod.rs:1824
  10: <serde_json::de::Deserializer<R>>::f64_from_parts
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:679
  11: <serde_json::de::Deserializer<R>>::parse_exponent
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:500
  12: <serde_json::de::Deserializer<R>>::parse_decimal
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:450
  13: <serde_json::de::Deserializer<R>>::parse_number
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:399
  14: <serde_json::de::Deserializer<R>>::parse_integer
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:361
  15: <serde_json::de::Deserializer<R>>::deserialize_prim_number
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:267
  16: <&'a mut serde_json::de::Deserializer<R> as serde::de::Deserializer<'de>>::deserialize_f64
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:989
  17: serde::de::impls::<impl serde::de::Deserialize<'de> for f64>::deserialize
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.79/src/de/impls.rs:141
  18: serde_json::de::from_trait
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:2115
  19: serde_json::de::from_str
             at /home/mw/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.31/src/de.rs:2260
```


Discussion:
Thanks! Fixed in 1.0.32. How did you discover this bug?
I discovered it by fuzzying the following code with Honggfuzz:

```rust
#[derive(Serialize, Deserialize)]
struct Product {
    id: u64,
    name: String
}

fn fuzz_serde_json() {
    loop {
        fuzz!(|data: &[u8]| {
            let r: Result<Product, _> = serde_json::from_slice(data);
            match r {
                Ok(p) => (),
                Err(_) => ()
            }
        });
    }
}
```



Patch:
diff --git a/src/de.rs b/src/de.rs
index 70ebf0d5e..020869a64 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -676,7 +676,7 @@ impl<'de, R: Read<'de>> Deserializer<R> {
     ) -> Result<f64> {
         let mut f = significand as f64;
         loop {
-            match POW10.get(exponent.abs() as usize) {
+            match POW10.get(exponent.wrapping_abs() as usize) {
                 Some(&pow) => {
                     if exponent >= 0 {
                         f *= pow;


Test patch:
diff --git a/tests/test.rs b/tests/test.rs
index 954ac901b..688dfe5db 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -860,6 +860,7 @@ fn test_parse_f64() {
         ("0.00e00", 0.0),
         ("0.00e+00", 0.0),
         ("0.00e-00", 0.0),
+        ("3.5E-2147483647", 0.0),
         (
             &format!("{}", (i64::MIN as f64) - 1.0),
             (i64::MIN as f64) - 1.0,