Skip to content

Commit 708811d

Browse files
committed
More specific InputTooShort
1 parent 42347d8 commit 708811d

File tree

2 files changed

+72
-22
lines changed

2 files changed

+72
-22
lines changed

src/decode.rs

+68-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::types::Header;
22
use arrayvec::ArrayVec;
33
use bytes::{Buf, Bytes, BytesMut};
4-
use core::any::Any;
4+
use core::{any::Any, num::NonZeroUsize};
55

66
pub trait Decodable: Sized {
77
fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError>;
@@ -80,7 +80,7 @@ mod alloc_impl {
8080
pub enum DecodeError {
8181
Overflow,
8282
LeadingZero,
83-
InputTooShort,
83+
InputTooShort { needed: Option<NonZeroUsize> },
8484
NonCanonicalSingleByte,
8585
NonCanonicalSize,
8686
UnexpectedLength,
@@ -98,7 +98,14 @@ impl core::fmt::Display for DecodeError {
9898
match self {
9999
DecodeError::Overflow => write!(f, "overflow"),
100100
DecodeError::LeadingZero => write!(f, "leading zero"),
101-
DecodeError::InputTooShort => write!(f, "input too short"),
101+
DecodeError::InputTooShort { needed } => {
102+
write!(f, "input too short")?;
103+
if let Some(needed) = needed {
104+
write!(f, ": need {needed} more bytes")?;
105+
}
106+
107+
Ok(())
108+
}
102109
DecodeError::NonCanonicalSingleByte => write!(f, "non-canonical single byte"),
103110
DecodeError::NonCanonicalSize => write!(f, "non-canonical size"),
104111
DecodeError::UnexpectedLength => write!(f, "unexpected length"),
@@ -115,7 +122,7 @@ impl core::fmt::Display for DecodeError {
115122
impl Header {
116123
pub fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
117124
if !buf.has_remaining() {
118-
return Err(DecodeError::InputTooShort);
125+
return Err(DecodeError::InputTooShort { needed: None });
119126
}
120127

121128
let b = buf[0];
@@ -134,7 +141,7 @@ impl Header {
134141

135142
if h.payload_length == 1 {
136143
if !buf.has_remaining() {
137-
return Err(DecodeError::InputTooShort);
144+
return Err(DecodeError::InputTooShort { needed: None });
138145
}
139146
if buf[0] < 0x80 {
140147
return Err(DecodeError::NonCanonicalSingleByte);
@@ -145,8 +152,13 @@ impl Header {
145152
} else if b < 0xC0 {
146153
buf.advance(1);
147154
let len_of_len = b as usize - 0xB7;
148-
if buf.len() < len_of_len {
149-
return Err(DecodeError::InputTooShort);
155+
if let Some(needed) = len_of_len
156+
.checked_sub(buf.len())
157+
.and_then(NonZeroUsize::new)
158+
{
159+
return Err(DecodeError::InputTooShort {
160+
needed: Some(needed),
161+
});
150162
}
151163
let payload_length = usize::try_from(u64::from_be_bytes(
152164
static_left_pad(&buf[..len_of_len]).ok_or(DecodeError::LeadingZero)?,
@@ -171,8 +183,13 @@ impl Header {
171183
buf.advance(1);
172184
let list = true;
173185
let len_of_len = b as usize - 0xF7;
174-
if buf.len() < len_of_len {
175-
return Err(DecodeError::InputTooShort);
186+
if let Some(needed) = len_of_len
187+
.checked_sub(buf.len())
188+
.and_then(NonZeroUsize::new)
189+
{
190+
return Err(DecodeError::InputTooShort {
191+
needed: Some(needed),
192+
});
176193
}
177194
let payload_length = usize::try_from(u64::from_be_bytes(
178195
static_left_pad(&buf[..len_of_len]).ok_or(DecodeError::LeadingZero)?,
@@ -190,8 +207,14 @@ impl Header {
190207
}
191208
};
192209

193-
if buf.remaining() < h.payload_length {
194-
return Err(DecodeError::InputTooShort);
210+
if let Some(needed) = h
211+
.payload_length
212+
.checked_sub(buf.remaining())
213+
.and_then(NonZeroUsize::new)
214+
{
215+
return Err(DecodeError::InputTooShort {
216+
needed: Some(needed),
217+
});
195218
}
196219

197220
Ok(h)
@@ -228,8 +251,14 @@ macro_rules! decode_integer {
228251
if h.payload_length > (<$t>::BITS as usize / 8) {
229252
return Err(DecodeError::Overflow);
230253
}
231-
if buf.remaining() < h.payload_length {
232-
return Err(DecodeError::InputTooShort);
254+
if let Some(needed) = h
255+
.payload_length
256+
.checked_sub(buf.remaining())
257+
.and_then(NonZeroUsize::new)
258+
{
259+
return Err(DecodeError::InputTooShort {
260+
needed: Some(needed),
261+
});
233262
}
234263
let v = <$t>::from_be_bytes(
235264
static_left_pad(&buf[..h.payload_length]).ok_or(DecodeError::LeadingZero)?,
@@ -296,8 +325,14 @@ mod ethereum_types_support {
296325
if h.payload_length > $n_bytes {
297326
return Err(DecodeError::Overflow);
298327
}
299-
if buf.remaining() < h.payload_length {
300-
return Err(DecodeError::InputTooShort);
328+
if let Some(needed) = h
329+
.payload_length
330+
.checked_sub(buf.remaining())
331+
.and_then(NonZeroUsize::new)
332+
{
333+
return Err(DecodeError::InputTooShort {
334+
needed: Some(needed),
335+
});
301336
}
302337
let n = <$t>::from_big_endian(
303338
&static_left_pad::<$n_bytes>(&buf[..h.payload_length])
@@ -494,7 +529,9 @@ mod tests {
494529
&hex!("8AFFFFFFFFFFFFFFFFFF7C")[..],
495530
),
496531
(
497-
Err(DecodeError::InputTooShort),
532+
Err(DecodeError::InputTooShort {
533+
needed: Some(NonZeroUsize::new(1).unwrap()),
534+
}),
498535
&hex!("8BFFFFFFFFFFFFFFFFFF7C")[..],
499536
),
500537
(Err(DecodeError::UnexpectedList), &hex!("C0")[..]),
@@ -521,7 +558,9 @@ mod tests {
521558
&hex!("8AFFFFFFFFFFFFFFFFFF7C")[..],
522559
),
523560
(
524-
Err(DecodeError::InputTooShort),
561+
Err(DecodeError::InputTooShort {
562+
needed: Some(NonZeroUsize::new(1).unwrap()),
563+
}),
525564
&hex!("8BFFFFFFFFFFFFFFFFFF7C")[..],
526565
),
527566
(Err(DecodeError::UnexpectedList), &hex!("C0")[..]),
@@ -549,7 +588,9 @@ mod tests {
549588
&hex!("8AFFFFFFFFFFFFFFFFFF7C")[..],
550589
),
551590
(
552-
Err(DecodeError::InputTooShort),
591+
Err(DecodeError::InputTooShort {
592+
needed: Some(NonZeroUsize::new(1).unwrap()),
593+
}),
553594
&hex!("8BFFFFFFFFFFFFFFFFFF7C")[..],
554595
),
555596
(Err(DecodeError::UnexpectedList), &hex!("C0")[..]),
@@ -577,7 +618,9 @@ mod tests {
577618
&hex!("8AFFFFFFFFFFFFFFFFFF7C")[..],
578619
),
579620
(
580-
Err(DecodeError::InputTooShort),
621+
Err(DecodeError::InputTooShort {
622+
needed: Some(NonZeroUsize::new(1).unwrap()),
623+
}),
581624
&hex!("8BFFFFFFFFFFFFFFFFFF7C")[..],
582625
),
583626
(Err(DecodeError::UnexpectedList), &hex!("C0")[..]),
@@ -605,7 +648,9 @@ mod tests {
605648
&hex!("8AFFFFFFFFFFFFFFFFFF7C")[..],
606649
),
607650
(
608-
Err(DecodeError::InputTooShort),
651+
Err(DecodeError::InputTooShort {
652+
needed: Some(NonZeroUsize::new(1).unwrap()),
653+
}),
609654
&hex!("8BFFFFFFFFFFFFFFFFFF7C")[..],
610655
),
611656
(Err(DecodeError::UnexpectedList), &hex!("C0")[..]),
@@ -633,7 +678,9 @@ mod tests {
633678
&hex!("8AFFFFFFFFFFFFFFFFFF7C")[..],
634679
),
635680
(
636-
Err(DecodeError::InputTooShort),
681+
Err(DecodeError::InputTooShort{
682+
needed: Some(NonZeroUsize::new(1).unwrap()),
683+
}),
637684
&hex!("8BFFFFFFFFFFFFFFFFFF7C")[..],
638685
),
639686
(Err(DecodeError::UnexpectedList), &hex!("C0")[..]),

tests/rlp.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use bytes::{Bytes, BytesMut};
33
use ethnum::U256;
44
use fastrlp::*;
55
use hex_literal::hex;
6+
use std::num::NonZeroUsize;
67

78
#[derive(Debug, PartialEq, Encodable, Decodable)]
89
struct Item {
@@ -96,7 +97,9 @@ fn invalid_decode_sideeffect() {
9697

9798
assert_eq!(
9899
Test4Numbers::decode(&mut sl),
99-
Err(DecodeError::InputTooShort)
100+
Err(DecodeError::InputTooShort {
101+
needed: Some(NonZeroUsize::new(1).unwrap())
102+
})
100103
);
101104

102105
assert_eq!(sl.len(), fixture.len());

0 commit comments

Comments
 (0)