177 invalid encodings (#212)

* split out invalid encoding errors

* detail breaking changes
This commit is contained in:
Ty Overby 2017-10-12 09:04:14 -07:00 committed by GitHub
parent 45e70e297e
commit c8f02e30aa
5 changed files with 56 additions and 53 deletions

View File

@ -3,6 +3,7 @@ name = "bincode"
version = "0.8.1"
authors = ["Ty Overby <ty@pre-alpha.com>", "Francesco Mazzoli <f@mazzo.li>", "David Tolnay <dtolnay@gmail.com>", "Daniel Griffen"]
# Adding ErrorKind::Invalid*Encoding is a breaking change
# Adding ErrorKind::DeserializeAnyNotSupported is a breaking change
publish = false

View File

@ -56,11 +56,9 @@ impl<'de, R: BincodeRead<'de>, E: ByteOrder, S: SizeLimit> Deserializer<R, S, E>
}
fn read_string(&mut self) -> Result<String> {
String::from_utf8(try!(self.read_vec())).map_err(|err|
ErrorKind::InvalidEncoding{
desc: "error while decoding utf8 string",
detail: Some(format!("Deserialize error: {}", err))
}.into())
let vec = self.read_vec()?;
String::from_utf8(vec).map_err(|e|
ErrorKind::InvalidUtf8Encoding(e.utf8_error()).into())
}
}
@ -96,10 +94,7 @@ where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder {
1 => visitor.visit_bool(true),
0 => visitor.visit_bool(false),
value => {
Err(ErrorKind::InvalidEncoding{
desc: "invalid u8 when decoding bool",
detail: Some(format!("Expected 0 or 1, got {}", value))
}.into())
Err(ErrorKind::InvalidBoolEncoding(value).into())
}
}
}
@ -142,10 +137,7 @@ where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder {
use std::str;
let error = || {
ErrorKind::InvalidEncoding{
desc: "invalid char encoding",
detail: None,
}.into()
ErrorKind::InvalidCharEncoding.into()
};
let mut buf = [0u8; 4];
@ -255,10 +247,7 @@ where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder {
match value {
0 => visitor.visit_none(),
1 => visitor.visit_some(&mut *self),
_ => Err(ErrorKind::InvalidEncoding{
desc: "invalid tag when decoding Option",
detail: Some(format!("Expected 0 or 1, got {}", value))
}.into()),
v => Err(ErrorKind::InvalidTagEncoding(v as usize).into())
}
}

View File

@ -81,10 +81,7 @@ impl <'storage> BincodeRead<'storage> for SliceReader<'storage> {
let string = match ::std::str::from_utf8(&self.slice[..length]) {
Ok(s) => s,
Err(_) => return Err(Box::new(ErrorKind::InvalidEncoding {
desc: "string was not valid utf8",
detail: None,
})),
Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()),
};
let r = visitor.visit_borrowed_str(string);
self.slice = &self.slice[length..];
@ -133,10 +130,7 @@ impl <R> BincodeRead<'static> for IoReader<R> where R: io::Read {
let string = match ::std::str::from_utf8(&self.temp_buffer[..length]) {
Ok(s) => s,
Err(_) => return Err(Box::new(::ErrorKind::InvalidEncoding {
desc: "string was not valid utf8",
detail: None,
})),
Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()),
};
let r = visitor.visit_str(string);

View File

@ -4,8 +4,10 @@
use std::io::{self, Write, Read};
use std::{error, fmt, result};
use std::str::Utf8Error;
use ::{CountSize, SizeLimit};
use byteorder::{ByteOrder};
use std::error::Error as StdError;
pub use super::de::{
Deserializer,
@ -31,16 +33,16 @@ pub enum ErrorKind {
/// If the error stems from the reader/writer that is being used
/// during (de)serialization, that error will be stored and returned here.
Io(io::Error),
/// If the bytes in the reader are not decodable because of an invalid
/// encoding, this error will be returned. This error is only possible
/// if a stream is corrupted. A stream produced from `encode` or `encode_into`
/// should **never** produce an InvalidEncoding error.
InvalidEncoding {
#[allow(missing_docs)]
desc: &'static str,
#[allow(missing_docs)]
detail: Option<String>
},
/// Returned if the deserializer attempts to deserialize a string that is not valid utf8
InvalidUtf8Encoding(Utf8Error),
/// Returned if the deserializer attempts to deserialize a bool that was
/// not encoded as either a 1 or a 0
InvalidBoolEncoding(u8),
/// Returned if the deserializer attempts to deserialize a char that is not in the correct format.
InvalidCharEncoding,
/// Returned if the deserializer attempts to deserialize the tag of an enum that is
/// not in the expected ranges
InvalidTagEncoding(usize),
/// Serde has a deserialize_any method that lets the format hint to the
/// object which route to take in deserializing.
DeserializeAnyNotSupported,
@ -53,11 +55,14 @@ pub enum ErrorKind {
Custom(String)
}
impl error::Error for ErrorKind {
impl StdError for ErrorKind {
fn description(&self) -> &str {
match *self {
ErrorKind::Io(ref err) => error::Error::description(err),
ErrorKind::InvalidEncoding{desc, ..} => desc,
ErrorKind::InvalidUtf8Encoding(_) => "string is not valid utf8",
ErrorKind::InvalidBoolEncoding(_) => "invalid u8 while decoding bool",
ErrorKind::InvalidCharEncoding => "char is not valid",
ErrorKind::InvalidTagEncoding(_) => "tag for enum is not valid",
ErrorKind::SequenceMustHaveLength => "bincode can't encode infinite sequences",
ErrorKind::DeserializeAnyNotSupported => "bincode doesn't support serde::Deserializer::deserialize_any",
ErrorKind::SizeLimit => "the size limit for decoding has been reached",
@ -69,7 +74,10 @@ impl error::Error for ErrorKind {
fn cause(&self) -> Option<&error::Error> {
match *self {
ErrorKind::Io(ref err) => Some(err),
ErrorKind::InvalidEncoding{..} => None,
ErrorKind::InvalidUtf8Encoding(_) => None,
ErrorKind::InvalidBoolEncoding(_) => None,
ErrorKind::InvalidCharEncoding => None,
ErrorKind::InvalidTagEncoding(_) => None,
ErrorKind::SequenceMustHaveLength => None,
ErrorKind::DeserializeAnyNotSupported => None,
ErrorKind::SizeLimit => None,
@ -89,10 +97,14 @@ impl fmt::Display for ErrorKind {
match *self {
ErrorKind::Io(ref ioerr) =>
write!(fmt, "io error: {}", ioerr),
ErrorKind::InvalidEncoding{desc, detail: None}=>
write!(fmt, "invalid encoding: {}", desc),
ErrorKind::InvalidEncoding{desc, detail: Some(ref detail)}=>
write!(fmt, "invalid encoding: {} ({})", desc, detail),
ErrorKind::InvalidUtf8Encoding(ref e) =>
write!(fmt, "{}: {}", self.description(), e),
ErrorKind::InvalidBoolEncoding(b) =>
write!(fmt, "{}, expected 0 or 1, found {}", self.description(), b),
ErrorKind::InvalidCharEncoding =>
write!(fmt, "{}", self.description()),
ErrorKind::InvalidTagEncoding(tag) =>
write!(fmt, "{}, found {}", self.description(), tag),
ErrorKind::SequenceMustHaveLength =>
write!(fmt, "bincode can only encode sequences and maps that have a knowable size ahead of time."),
ErrorKind::SizeLimit =>

View File

@ -195,25 +195,32 @@ fn test_fixed_size_array() {
#[test]
fn deserializing_errors() {
fn isize_invalid_deserialize<T: Debug>(res: Result<T>) {
match res.map_err(|e| *e) {
Err(ErrorKind::InvalidEncoding{..}) => {},
Err(ErrorKind::Custom(ref s)) if s.contains("invalid encoding") => {},
Err(ErrorKind::Custom(ref s)) if s.contains("invalid value") => {},
other => panic!("Expecting InvalidEncoding, got {:?}", other),
}
match *deserialize_little::<bool>(&vec![0xA][..]).unwrap_err() {
ErrorKind::InvalidBoolEncoding(0xA) => {},
_ => panic!(),
}
match *deserialize_little::<String>(&vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF][..]).unwrap_err() {
ErrorKind::InvalidUtf8Encoding(_) => {},
_ => panic!(),
}
isize_invalid_deserialize(deserialize_little::<bool>(&vec![0xA][..]));
isize_invalid_deserialize(deserialize_little::<String>(&vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF][..]));
// Out-of-bounds variant
#[derive(Serialize, Deserialize, Debug)]
enum Test {
One,
Two,
};
isize_invalid_deserialize(deserialize_little::<Test>(&vec![0, 0, 0, 5][..]));
isize_invalid_deserialize(deserialize_little::<Option<u8>>(&vec![5, 0][..]));
match *deserialize_little::<Test>(&vec![0, 0, 0, 5][..]).unwrap_err() {
// Error message comes from serde
ErrorKind::Custom(_) => {},
_ => panic!(),
}
match *deserialize_little::<Option<u8>>(&vec![5, 0][..]).unwrap_err() {
ErrorKind::InvalidTagEncoding(_) => {},
_ => panic!(),
}
}
#[test]