Reject trailing bytes (#198)
This commit is contained in:
parent
1bc63deb73
commit
e80f61b9da
|
|
@ -49,6 +49,7 @@ macro_rules! config_map {
|
|||
(Unlimited, Little) => {
|
||||
let $opts = DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.with_no_limit()
|
||||
.with_little_endian();
|
||||
$call
|
||||
|
|
@ -56,6 +57,7 @@ macro_rules! config_map {
|
|||
(Unlimited, Big) => {
|
||||
let $opts = DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.with_no_limit()
|
||||
.with_big_endian();
|
||||
$call
|
||||
|
|
@ -63,6 +65,7 @@ macro_rules! config_map {
|
|||
(Unlimited, Native) => {
|
||||
let $opts = DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.with_no_limit()
|
||||
.with_native_endian();
|
||||
$call
|
||||
|
|
@ -71,6 +74,7 @@ macro_rules! config_map {
|
|||
(Limited(l), Little) => {
|
||||
let $opts = DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.with_limit(l)
|
||||
.with_little_endian();
|
||||
$call
|
||||
|
|
@ -78,6 +82,7 @@ macro_rules! config_map {
|
|||
(Limited(l), Big) => {
|
||||
let $opts = DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.with_limit(l)
|
||||
.with_big_endian();
|
||||
$call
|
||||
|
|
@ -85,6 +90,7 @@ macro_rules! config_map {
|
|||
(Limited(l), Native) => {
|
||||
let $opts = DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.with_limit(l)
|
||||
.with_native_endian();
|
||||
$call
|
||||
|
|
|
|||
|
|
@ -8,16 +8,19 @@ pub(crate) use self::endian::BincodeByteOrder;
|
|||
pub(crate) use self::int::IntEncoding;
|
||||
pub(crate) use self::internal::*;
|
||||
pub(crate) use self::limit::SizeLimit;
|
||||
pub(crate) use self::trailing::TrailingBytes;
|
||||
|
||||
pub use self::endian::{BigEndian, LittleEndian, NativeEndian};
|
||||
pub use self::int::{FixintEncoding, VarintEncoding};
|
||||
pub use self::legacy::*;
|
||||
pub use self::limit::{Bounded, Infinite};
|
||||
pub use self::trailing::{AllowTrailing, RejectTrailing};
|
||||
|
||||
mod endian;
|
||||
mod int;
|
||||
mod legacy;
|
||||
mod limit;
|
||||
mod trailing;
|
||||
|
||||
/// The default options for bincode serialization/deserialization.
|
||||
///
|
||||
|
|
@ -50,6 +53,7 @@ impl InternalOptions for DefaultOptions {
|
|||
type Limit = Infinite;
|
||||
type Endian = LittleEndian;
|
||||
type IntEncoding = VarintEncoding;
|
||||
type Trailing = RejectTrailing;
|
||||
|
||||
#[inline(always)]
|
||||
fn limit(&mut self) -> &mut Infinite {
|
||||
|
|
@ -111,6 +115,16 @@ pub trait Options: InternalOptions + Sized {
|
|||
WithOtherIntEncoding::new(self)
|
||||
}
|
||||
|
||||
/// Sets the deserializer to reject trailing bytes
|
||||
fn reject_trailing_bytes(self) -> WithOtherTrailing<Self, RejectTrailing> {
|
||||
WithOtherTrailing::new(self)
|
||||
}
|
||||
|
||||
/// Sets the deserializer to allow trailing bytes
|
||||
fn allow_trailing_bytes(self) -> WithOtherTrailing<Self, AllowTrailing> {
|
||||
WithOtherTrailing::new(self)
|
||||
}
|
||||
|
||||
/// Serializes a serializable object into a `Vec` of bytes using this configuration
|
||||
#[inline(always)]
|
||||
fn serialize<S: ?Sized + serde::Serialize>(self, t: &S) -> Result<Vec<u8>> {
|
||||
|
|
@ -229,6 +243,12 @@ pub struct WithOtherIntEncoding<O: Options, I: IntEncoding> {
|
|||
_length: PhantomData<I>,
|
||||
}
|
||||
|
||||
/// A configuration struct with a user-specified trailing bytes behavior.
|
||||
pub struct WithOtherTrailing<O: Options, T: TrailingBytes> {
|
||||
options: O,
|
||||
_trailing: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<O: Options, L: SizeLimit> WithOtherLimit<O, L> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new(options: O, limit: L) -> WithOtherLimit<O, L> {
|
||||
|
|
@ -259,11 +279,21 @@ impl<O: Options, I: IntEncoding> WithOtherIntEncoding<O, I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<O: Options, T: TrailingBytes> WithOtherTrailing<O, T> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new(options: O) -> WithOtherTrailing<O, T> {
|
||||
WithOtherTrailing {
|
||||
options,
|
||||
_trailing: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Options, E: BincodeByteOrder + 'static> InternalOptions for WithOtherEndian<O, E> {
|
||||
type Limit = O::Limit;
|
||||
type Endian = E;
|
||||
type IntEncoding = O::IntEncoding;
|
||||
|
||||
type Trailing = O::Trailing;
|
||||
#[inline(always)]
|
||||
fn limit(&mut self) -> &mut O::Limit {
|
||||
self.options.limit()
|
||||
|
|
@ -274,7 +304,7 @@ impl<O: Options, L: SizeLimit + 'static> InternalOptions for WithOtherLimit<O, L
|
|||
type Limit = L;
|
||||
type Endian = O::Endian;
|
||||
type IntEncoding = O::IntEncoding;
|
||||
|
||||
type Trailing = O::Trailing;
|
||||
fn limit(&mut self) -> &mut L {
|
||||
&mut self.new_limit
|
||||
}
|
||||
|
|
@ -284,6 +314,18 @@ impl<O: Options, I: IntEncoding + 'static> InternalOptions for WithOtherIntEncod
|
|||
type Limit = O::Limit;
|
||||
type Endian = O::Endian;
|
||||
type IntEncoding = I;
|
||||
type Trailing = O::Trailing;
|
||||
|
||||
fn limit(&mut self) -> &mut O::Limit {
|
||||
self.options.limit()
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Options, T: TrailingBytes + 'static> InternalOptions for WithOtherTrailing<O, T> {
|
||||
type Limit = O::Limit;
|
||||
type Endian = O::Endian;
|
||||
type IntEncoding = O::IntEncoding;
|
||||
type Trailing = T;
|
||||
|
||||
fn limit(&mut self) -> &mut O::Limit {
|
||||
self.options.limit()
|
||||
|
|
@ -297,6 +339,7 @@ mod internal {
|
|||
type Limit: SizeLimit + 'static;
|
||||
type Endian: BincodeByteOrder + 'static;
|
||||
type IntEncoding: IntEncoding + 'static;
|
||||
type Trailing: TrailingBytes + 'static;
|
||||
|
||||
fn limit(&mut self) -> &mut Self::Limit;
|
||||
}
|
||||
|
|
@ -305,6 +348,7 @@ mod internal {
|
|||
type Limit = O::Limit;
|
||||
type Endian = O::Endian;
|
||||
type IntEncoding = O::IntEncoding;
|
||||
type Trailing = O::Trailing;
|
||||
|
||||
#[inline(always)]
|
||||
fn limit(&mut self) -> &mut Self::Limit {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
use de::read::SliceReader;
|
||||
use {ErrorKind, Result};
|
||||
|
||||
/// A trait for erroring deserialization if not all bytes were read.
|
||||
pub trait TrailingBytes {
|
||||
/// Checks a given slice reader to determine if deserialization used all bytes in the slice.
|
||||
fn check_end(reader: &SliceReader) -> Result<()>;
|
||||
}
|
||||
|
||||
/// A TrailingBytes config that will allow trailing bytes in slices after deserialization.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AllowTrailing;
|
||||
|
||||
/// A TrailingBytes config that will cause bincode to produce an error if bytes are left over in the slice when deserialization is complete.
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RejectTrailing;
|
||||
|
||||
impl TrailingBytes for AllowTrailing {
|
||||
#[inline(always)]
|
||||
fn check_end(_reader: &SliceReader) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TrailingBytes for RejectTrailing {
|
||||
#[inline(always)]
|
||||
fn check_end(reader: &SliceReader) -> Result<()> {
|
||||
if reader.is_finished() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Box::new(ErrorKind::Custom(
|
||||
"Slice had bytes remaining after deserialization".to_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ pub mod read;
|
|||
/// let bytes_read = d.bytes_read();
|
||||
/// ```
|
||||
pub struct Deserializer<R, O: Options> {
|
||||
reader: R,
|
||||
pub(crate) reader: R,
|
||||
options: O,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ impl<'storage> SliceReader<'storage> {
|
|||
self.slice = remaining;
|
||||
Ok(read_slice)
|
||||
}
|
||||
|
||||
pub(crate) fn is_finished(&self) -> bool {
|
||||
self.slice.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IoReader<R> {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use serde;
|
|||
use std::io::{Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use config::{Infinite, InternalOptions, Options, SizeLimit};
|
||||
use config::{Infinite, InternalOptions, Options, SizeLimit, TrailingBytes};
|
||||
use de::read::BincodeRead;
|
||||
use Result;
|
||||
|
||||
|
|
@ -111,7 +111,14 @@ where
|
|||
T: serde::de::DeserializeSeed<'a>,
|
||||
O: InternalOptions,
|
||||
{
|
||||
let reader = ::de::read::SliceReader::new(bytes);
|
||||
let options = ::config::WithOtherLimit::new(options, Infinite);
|
||||
deserialize_from_custom_seed(seed, reader, options)
|
||||
|
||||
let reader = ::de::read::SliceReader::new(bytes);
|
||||
let mut deserializer = ::de::Deserializer::with_bincode_read(reader, options);
|
||||
let val = seed.deserialize(&mut deserializer)?;
|
||||
|
||||
match O::Trailing::check_end(&deserializer.reader) {
|
||||
Ok(_) => Ok(val),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ where
|
|||
{
|
||||
DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.serialize(value)
|
||||
}
|
||||
|
||||
|
|
@ -107,6 +108,7 @@ where
|
|||
{
|
||||
DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.deserialize_from(reader)
|
||||
}
|
||||
|
||||
|
|
@ -122,6 +124,7 @@ where
|
|||
{
|
||||
DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.deserialize_from_custom(reader)
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +139,7 @@ where
|
|||
{
|
||||
DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.deserialize_in_place(reader, place)
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +150,7 @@ where
|
|||
{
|
||||
DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.deserialize(bytes)
|
||||
}
|
||||
|
||||
|
|
@ -156,5 +161,6 @@ where
|
|||
{
|
||||
DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.allow_trailing_bytes()
|
||||
.serialized_size(value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,6 +277,17 @@ fn deserializing_errors() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bytes() {
|
||||
match DefaultOptions::new()
|
||||
.deserialize::<char>(b"1x")
|
||||
.map_err(|e| *e)
|
||||
{
|
||||
Err(ErrorKind::Custom(_)) => {}
|
||||
other => panic!("Expecting TrailingBytes, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn too_big_deserialize() {
|
||||
let serialized = vec![0, 0, 0, 3];
|
||||
|
|
|
|||
Loading…
Reference in New Issue