Improved de/serialise error messages

Fortune for rsh's current commit: Half curse − 半凶
complex-cap
Avril 3 years ago
parent 46cd0e4a9f
commit 37a00d1099
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -9,6 +9,25 @@ use bytes::{
Buf,
};
macro_rules! try_from {
(ref $into:ty, $from:expr $(; $fmt:literal)?) => {
{
let from = &$from;
#[inline] fn _type_name_of_val<T: ?Sized>(_: &T) -> &'static str
{
::std::any::type_name::<T>()
}
<$into>::try_from(*from).wrap_err(eyre!("Failed to convert type"))
.with_section(|| ::std::any::type_name::<$into>().header("New type"))
.with_section(|| _type_name_of_val(from).header("Old type"))
.with_section(|| from.to_string().header("Value was"))
}
};
}
/// Check bit written/read from binary streams to check basic integrity.
pub const MESSAGE_HEADER_CHECK: [u8; 4] = (0xc0ffee00u32).to_be_bytes();
impl<V: ?Sized> SerializedMessage<V>
{
/// Write this message to a buffer
@ -41,15 +60,22 @@ impl<V: ?Sized> SerializedMessage<V>
(: $ser:expr) => {
{
let mut v = StackVec::new();
serde_cbor::to_writer(&mut v, $ser)?;
buffer.put_u64(v.len().try_into()?);
#[inline] fn _type_name_of_val<T: ?Sized>(_: &T) -> &'static str
{
::std::any::type_name::<T>()
}
let ser = $ser;
serde_cbor::to_writer(&mut v, $ser)
.wrap_err(eyre!("Failed to serialise value to temporary buffer"))
.with_section(|| _type_name_of_val(ser).header("Type was"))?;
buffer.put_u64(try_from!(ref u64, v.len())?);
write!(&v[..]);
}
};
}
write!(MESSAGE_HEADER_CHECK);
write!(: &self.header);
buffer.put_u64(self.data.len().try_into()?);
buffer.put_u64(try_from!(ref u64, self.data.len())?);
write!(self.data);
write!(self.hash);
write!(? self.enc_key);
@ -93,21 +119,21 @@ impl<V: ?Sized + MessageValue> SerializedMessage<V>
Some(def)
},
x => {
return Err(eyre!("Invalid optional-set bit: {}", x));
return Err(eyre!("Invalid optional-set bit (should be 0 or 1)").with_section(|| x.header("Value was")));
}
}
}
};
(: $ser:ty) => {
{
let len = usize::try_from(bytes.get_u64())?;
let len = try_from!(ref usize, bytes.get_u64())?;
if len > MAX_ALLOC_SIZE {
return Err(eyre!("Invalid length read: {}", len)
.with_section(|| format!("Max length read: {}", MAX_ALLOC_SIZE)))
}
alloc_local_bytes(len, |de| {
read!(&mut de[..]);
serde_cbor::from_slice::<$ser>(&de[..]).wrap_err(eyre!("Failed to deserialise {} from reader", std::any::type_name::<$ser>()))
serde_cbor::from_slice::<$ser>(&de[..]).wrap_err(eyre!("Failed to deserialise CBOR from reader")).with_section(|| std::any::type_name::<$ser>().header("Type to deserialise was"))
})?
}
@ -120,13 +146,22 @@ impl<V: ?Sized + MessageValue> SerializedMessage<V>
}
}
}
let mut check = [0u8; MESSAGE_HEADER_CHECK.len()];
read!(&mut check[..]);
if check != MESSAGE_HEADER_CHECK {
return Err(eyre!("Invalid check bit for message header"))
.with_section(|| u32::from_be_bytes(check).header("Expected"))
.with_section(|| u32::from_be_bytes(MESSAGE_HEADER_CHECK).header("Got"));
}
let header = read!(: SerHeader);
let data_len = usize::try_from(bytes.get_u64())?;
let data_len = try_from!(ref usize, bytes.get_u64())?;
let mut data = Vec::with_capacity(std::cmp::min(data_len, MAX_ALLOC_SIZE)); //XXX: Redesign so we don't allocate OR try to read massive buffers by accident on corrupted/malformed messages
read!(&mut data, data_len);
if data.len()!=data_len {
return Err(eyre!("Failed to read {} bytes from buffer (got {})", data_len, data.len()));
return Err(eyre!("Failed to read body bytes from buffer"))
.with_section(|| format!("{} bytes", data_len).header("Tried to read"))
.with_section(|| format!("{} bytes", data.len()).header("Read only"));
}
let mut hash = sha256::Sha256Hash::default();
read!(&mut hash);

Loading…
Cancel
Save