From 5e5d7440351a003aa79c49702c404ec670fe09ec Mon Sep 17 00:00:00 2001 From: nuskey8 Date: Sun, 26 Jul 2026 14:21:17 +0900 Subject: [PATCH 1/2] fix: cap BufRead payload preallocation --- zerompk/src/bufread.rs | 3 ++- zerompk/tests/deserialize.rs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/zerompk/src/bufread.rs b/zerompk/src/bufread.rs index fcea569..3e5007c 100644 --- a/zerompk/src/bufread.rs +++ b/zerompk/src/bufread.rs @@ -80,7 +80,8 @@ impl<'a, R: std::io::BufRead> BufReadReader<'a, R> { #[inline(always)] fn take_vec(&mut self, len: usize) -> Result> { - let mut out = Vec::with_capacity(len); + const CHUNK_SIZE: usize = 8192; + let mut out = Vec::with_capacity(len.min(CHUNK_SIZE)); while out.len() < len { let buffer = self.window()?; let count = core::cmp::min(len - out.len(), buffer.len()); diff --git a/zerompk/tests/deserialize.rs b/zerompk/tests/deserialize.rs index f231048..54c937d 100644 --- a/zerompk/tests/deserialize.rs +++ b/zerompk/tests/deserialize.rs @@ -428,6 +428,23 @@ fn test_read_msgpack_bufread_skips_unknown_nested_value() { assert_eq!(decoded, BufReadKnownField { value: 42 }); } +#[test] +fn test_read_msgpack_bufread_rejects_truncated_huge_payloads_without_preallocating() { + let cases: &[&[u8]] = &[ + &[0xdb, 0xff, 0xff, 0xff, 0xff], + &[0xc6, 0xff, 0xff, 0xff, 0xff], + &[0xc9, 0xff, 0xff, 0xff, 0xff, 0x01], + ]; + + for data in cases { + let mut reader = BufReader::with_capacity(1, Cursor::new(*data)); + assert!(matches!( + zerompk::read_msgpack_bufread::<_, zerompk::Value<'_>>(&mut reader), + Err(zerompk::Error::BufferTooSmall) + )); + } +} + #[test] fn test_read_array_reuses_capacity() { let mut output = Vec::with_capacity(8); From 9e0d4bfbb413f8914a517f766151a4adf4446de4 Mon Sep 17 00:00:00 2001 From: nuskey8 Date: Sun, 26 Jul 2026 14:25:04 +0900 Subject: [PATCH 2/2] fix: cap BufRead deserialization preallocation --- zerompk/src/bufread.rs | 15 +++------------ zerompk/tests/deserialize.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/zerompk/src/bufread.rs b/zerompk/src/bufread.rs index 3e5007c..61ab090 100644 --- a/zerompk/src/bufread.rs +++ b/zerompk/src/bufread.rs @@ -594,19 +594,10 @@ impl<'de, R: std::io::BufRead> Read<'de> for BufReadReader<'_, R> { { out.clear(); let len = self.read_array_len()?; - if out.capacity() < len { - out.reserve(len); - } - let ptr = out.as_mut_ptr(); - for initialized in 0..len { + out.reserve(len.min(32)); + for _ in 0..len { match T::read(self) { - Ok(value) => unsafe { - // SAFETY: capacity is at least `len`; every slot is - // initialized once and exposed to Vec immediately so - // unwinding drops all initialized elements. - ptr.add(initialized).write(value); - out.set_len(initialized + 1); - }, + Ok(value) => out.push(value), Err(error) => { out.clear(); return Err(error); diff --git a/zerompk/tests/deserialize.rs b/zerompk/tests/deserialize.rs index 54c937d..0d8afe9 100644 --- a/zerompk/tests/deserialize.rs +++ b/zerompk/tests/deserialize.rs @@ -445,6 +445,17 @@ fn test_read_msgpack_bufread_rejects_truncated_huge_payloads_without_preallocati } } +#[test] +fn test_read_msgpack_bufread_rejects_truncated_huge_array_without_preallocating() { + let data = [0xdd, 0xff, 0xff, 0xff, 0xff]; + let mut reader = BufReader::with_capacity(1, Cursor::new(data.as_slice())); + + assert!(matches!( + zerompk::read_msgpack_bufread::<_, Vec>(&mut reader), + Err(zerompk::Error::BufferTooSmall) + )); +} + #[test] fn test_read_array_reuses_capacity() { let mut output = Vec::with_capacity(8);