mirror of https://git.sr.ht/~stygianentity/bincode
Return an error if a decoded slice length doesn't fit into usize (#491)
* Return an error if a decoded slice length doesn't fit into usize Bincode encodes a slice length, which is an usize, as an u64. When such an encoded slice length needs to be decoded it again uses an u64 but critically it truncates it into an usize. An usize is architecture dependent, it is the size how many bytes it takes to reference any location in memory. The most common sizes for an usize are 64, 32, and 16 bit. This might lead to silent data loss if the architecture that encoded the slice differs from the architecture that decoded the slice, i.e. if we go from a 64 bit architecture to a 32 or 16 bit one. Since bincode aims to be suitable for storage, aiming to support the exchange of data between different architectures silently truncating such slice lenghts should be avoided. This patch changes the behaviour to error out if we try to decode an slice lenght that can't fit into the current usize type. * Remove another two usize truncations * Rename the error variant if the usize doesn't fit anymore Co-authored-by: Trangar <victor.koenders@gmail.com>
This commit is contained in:
parent
306a772835
commit
d90f501872
|
|
@ -172,10 +172,15 @@ impl Decode for usize {
|
|||
IntEncoding::Fixed => {
|
||||
let mut bytes = [0u8; 8];
|
||||
decoder.reader().read(&mut bytes)?;
|
||||
Ok(match D::C::ENDIAN {
|
||||
|
||||
let value = match D::C::ENDIAN {
|
||||
Endian::Little => u64::from_le_bytes(bytes),
|
||||
Endian::Big => u64::from_be_bytes(bytes),
|
||||
} as usize)
|
||||
};
|
||||
|
||||
value
|
||||
.try_into()
|
||||
.map_err(|_| DecodeError::OutsideUsizeRange(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,7 +149,8 @@ pub trait Decoder: Sealed {
|
|||
/// # }
|
||||
/// impl<T: Decode> Decode for Container<T> {
|
||||
/// fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
|
||||
/// let len = u64::decode(decoder)? as usize;
|
||||
/// let len = u64::decode(decoder)?;
|
||||
/// let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?;
|
||||
/// // Make sure we don't allocate too much memory
|
||||
/// decoder.claim_bytes_read(len * core::mem::size_of::<T>());
|
||||
///
|
||||
|
|
@ -236,5 +237,7 @@ pub(crate) fn decode_option_variant<D: Decoder>(
|
|||
/// Decodes the length of any slice, container, etc from the decoder
|
||||
#[inline]
|
||||
pub(crate) fn decode_slice_len<D: Decoder>(decoder: &mut D) -> Result<usize, DecodeError> {
|
||||
u64::decode(decoder).map(|v| v as usize)
|
||||
let v = u64::decode(decoder)?;
|
||||
|
||||
v.try_into().map_err(|_| DecodeError::OutsideUsizeRange(v))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,14 @@ pub enum DecodeError {
|
|||
found: usize,
|
||||
},
|
||||
|
||||
/// The encoded value is outside of the range of the target usize type.
|
||||
///
|
||||
/// This can happen if an usize was encoded on an architecture with a larger
|
||||
/// usize type and then decoded on an architecture with a smaller one. For
|
||||
/// example going from a 64 bit architecture to a 32 or 16 bit one may
|
||||
/// cause this error.
|
||||
OutsideUsizeRange(u64),
|
||||
|
||||
/// Tried to decode an enum with no variants
|
||||
EmptyEnum {
|
||||
/// The type that was being decoded
|
||||
|
|
|
|||
Loading…
Reference in New Issue