From 5da52deaf8600f494c8034f52e21f511cfebd35f Mon Sep 17 00:00:00 2001 From: thiolliere Date: Tue, 25 Jun 2019 23:01:39 +0200 Subject: [PATCH 1/3] Cherry-pick max_decode_len patch to v4. --- src/codec.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index b76d6ecf..6636f679 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -18,6 +18,10 @@ use crate::alloc::vec::Vec; use crate::alloc::boxed::Box; use crate::alloc::collections::btree_map::BTreeMap; +/// When decoding input we don't allocate too much in advance so a small crafted input can't +/// trigger a big allocation. +const MAX_PREALLOCATION_SIZE: usize = 4 * 1024; + #[cfg(any(feature = "std", feature = "full"))] use crate::alloc::{ string::String, @@ -789,10 +793,32 @@ impl Decode for Vec { fn decode(input: &mut I) -> Option { >::decode(input).and_then(move |Compact(len)| { let len = len as usize; - let mut vec = vec![0; len]; - if input.read(&mut vec[..len]) != len { - None + + if len < MAX_PREALLOCATION_SIZE { + let mut vec = vec![0; len]; // len is ok here + if input.read(&mut vec[..]) != len { + None + } else { + Some(vec) + } } else { + // if len is considered too much for preallocation then use dynamic allocation + let mut vec = Vec::new(); + let mut remains = len; + let buffer_len = MAX_PREALLOCATION_SIZE; + let mut buffer = vec![0; buffer_len]; + + while remains != 0 { + let len_read = input.read(&mut buffer[..buffer_len.min(remains)]); + + if len_read == 0 { + return None + } + + remains -= len_read; + vec.extend_from_slice(&buffer[..len_read]); + } + Some(vec) } }) @@ -872,7 +898,11 @@ impl Encode for Vec { impl Decode for Vec { fn decode(input: &mut I) -> Option { >::decode(input).and_then(move |Compact(len)| { - let mut r = Vec::with_capacity(len as usize); + let max_pre_allocated_len = MAX_PREALLOCATION_SIZE.checked_div(mem::size_of::()) + .unwrap_or(0); + + let pre_allocated_len = (len as usize).min(max_pre_allocated_len); + let mut r = Vec::with_capacity(pre_allocated_len); for _ in 0..len { r.push(T::decode(input)?); } @@ -1507,4 +1537,18 @@ mod tests { CompactRef(&std::u64::MAX).using_encoded(|_| {}); CompactRef(&std::u128::MAX).using_encoded(|_| {}); } + + #[test] + fn encode_for_very_large_vec_works() { + let vec_u8: Vec = (0..MAX_PREALLOCATION_SIZE*3).map(|i| i as u8).collect(); + let vec_u16: Vec = (0..MAX_PREALLOCATION_SIZE*3).map(|i| i as u16).collect(); + assert_eq!(Vec::::decode(&mut &vec_u8.encode()[..][..]).unwrap(), vec_u8); + assert_eq!(Vec::::decode(&mut &vec_u16.encode()[..][..]).unwrap(), vec_u16); + } + + #[test] + fn encode_for_null_size_vec_works() { + let vec: Vec<()> = vec![(); 10]; + assert_eq!(Vec::<()>::decode(&mut &vec.encode()[..][..]).unwrap(), vec); + } } From e3ad771c18fc8adee1b5c70b0901dc251f692661 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 26 Jun 2019 12:08:25 +0200 Subject: [PATCH 2/3] bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 826dcf42..530f8bb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-codec" -version = "4.1.1-alpha.0" +version = "4.1.2" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "bitvec 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 09becb61..d137a60b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "parity-codec" description = "Lightweight, efficient, binary serialization and deserialization codec" -version = "4.1.1-alpha.0" +version = "4.1.2" authors = ["Parity Technologies "] license = "Apache-2.0" repository = "https://github.com/paritytech/parity-codec" From 6373ee0bb27a8f7c3199726e1c451066591e37d8 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 26 Jun 2019 12:16:22 +0200 Subject: [PATCH 3/3] Update version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 530f8bb9..c32597d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-codec" -version = "4.1.2" +version = "4.1.1" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "bitvec 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index d137a60b..dbca477e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "parity-codec" description = "Lightweight, efficient, binary serialization and deserialization codec" -version = "4.1.2" +version = "4.1.1" authors = ["Parity Technologies "] license = "Apache-2.0" repository = "https://github.com/paritytech/parity-codec"