mirror of https://git.sr.ht/~stygianentity/bincode
Reject trailing bytes (#198)
This commit is contained in:
parent
1bc63deb73
commit
e80f61b9da
|
|
@ -49,6 +49,7 @@ macro_rules! config_map {
|
||||||
(Unlimited, Little) => {
|
(Unlimited, Little) => {
|
||||||
let $opts = DefaultOptions::new()
|
let $opts = DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.with_no_limit()
|
.with_no_limit()
|
||||||
.with_little_endian();
|
.with_little_endian();
|
||||||
$call
|
$call
|
||||||
|
|
@ -56,6 +57,7 @@ macro_rules! config_map {
|
||||||
(Unlimited, Big) => {
|
(Unlimited, Big) => {
|
||||||
let $opts = DefaultOptions::new()
|
let $opts = DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.with_no_limit()
|
.with_no_limit()
|
||||||
.with_big_endian();
|
.with_big_endian();
|
||||||
$call
|
$call
|
||||||
|
|
@ -63,6 +65,7 @@ macro_rules! config_map {
|
||||||
(Unlimited, Native) => {
|
(Unlimited, Native) => {
|
||||||
let $opts = DefaultOptions::new()
|
let $opts = DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.with_no_limit()
|
.with_no_limit()
|
||||||
.with_native_endian();
|
.with_native_endian();
|
||||||
$call
|
$call
|
||||||
|
|
@ -71,6 +74,7 @@ macro_rules! config_map {
|
||||||
(Limited(l), Little) => {
|
(Limited(l), Little) => {
|
||||||
let $opts = DefaultOptions::new()
|
let $opts = DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.with_limit(l)
|
.with_limit(l)
|
||||||
.with_little_endian();
|
.with_little_endian();
|
||||||
$call
|
$call
|
||||||
|
|
@ -78,6 +82,7 @@ macro_rules! config_map {
|
||||||
(Limited(l), Big) => {
|
(Limited(l), Big) => {
|
||||||
let $opts = DefaultOptions::new()
|
let $opts = DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.with_limit(l)
|
.with_limit(l)
|
||||||
.with_big_endian();
|
.with_big_endian();
|
||||||
$call
|
$call
|
||||||
|
|
@ -85,6 +90,7 @@ macro_rules! config_map {
|
||||||
(Limited(l), Native) => {
|
(Limited(l), Native) => {
|
||||||
let $opts = DefaultOptions::new()
|
let $opts = DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.with_limit(l)
|
.with_limit(l)
|
||||||
.with_native_endian();
|
.with_native_endian();
|
||||||
$call
|
$call
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,19 @@ pub(crate) use self::endian::BincodeByteOrder;
|
||||||
pub(crate) use self::int::IntEncoding;
|
pub(crate) use self::int::IntEncoding;
|
||||||
pub(crate) use self::internal::*;
|
pub(crate) use self::internal::*;
|
||||||
pub(crate) use self::limit::SizeLimit;
|
pub(crate) use self::limit::SizeLimit;
|
||||||
|
pub(crate) use self::trailing::TrailingBytes;
|
||||||
|
|
||||||
pub use self::endian::{BigEndian, LittleEndian, NativeEndian};
|
pub use self::endian::{BigEndian, LittleEndian, NativeEndian};
|
||||||
pub use self::int::{FixintEncoding, VarintEncoding};
|
pub use self::int::{FixintEncoding, VarintEncoding};
|
||||||
pub use self::legacy::*;
|
pub use self::legacy::*;
|
||||||
pub use self::limit::{Bounded, Infinite};
|
pub use self::limit::{Bounded, Infinite};
|
||||||
|
pub use self::trailing::{AllowTrailing, RejectTrailing};
|
||||||
|
|
||||||
mod endian;
|
mod endian;
|
||||||
mod int;
|
mod int;
|
||||||
mod legacy;
|
mod legacy;
|
||||||
mod limit;
|
mod limit;
|
||||||
|
mod trailing;
|
||||||
|
|
||||||
/// The default options for bincode serialization/deserialization.
|
/// The default options for bincode serialization/deserialization.
|
||||||
///
|
///
|
||||||
|
|
@ -50,6 +53,7 @@ impl InternalOptions for DefaultOptions {
|
||||||
type Limit = Infinite;
|
type Limit = Infinite;
|
||||||
type Endian = LittleEndian;
|
type Endian = LittleEndian;
|
||||||
type IntEncoding = VarintEncoding;
|
type IntEncoding = VarintEncoding;
|
||||||
|
type Trailing = RejectTrailing;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn limit(&mut self) -> &mut Infinite {
|
fn limit(&mut self) -> &mut Infinite {
|
||||||
|
|
@ -111,6 +115,16 @@ pub trait Options: InternalOptions + Sized {
|
||||||
WithOtherIntEncoding::new(self)
|
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
|
/// Serializes a serializable object into a `Vec` of bytes using this configuration
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize<S: ?Sized + serde::Serialize>(self, t: &S) -> Result<Vec<u8>> {
|
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>,
|
_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> {
|
impl<O: Options, L: SizeLimit> WithOtherLimit<O, L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn new(options: O, limit: L) -> WithOtherLimit<O, L> {
|
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> {
|
impl<O: Options, E: BincodeByteOrder + 'static> InternalOptions for WithOtherEndian<O, E> {
|
||||||
type Limit = O::Limit;
|
type Limit = O::Limit;
|
||||||
type Endian = E;
|
type Endian = E;
|
||||||
type IntEncoding = O::IntEncoding;
|
type IntEncoding = O::IntEncoding;
|
||||||
|
type Trailing = O::Trailing;
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn limit(&mut self) -> &mut O::Limit {
|
fn limit(&mut self) -> &mut O::Limit {
|
||||||
self.options.limit()
|
self.options.limit()
|
||||||
|
|
@ -274,7 +304,7 @@ impl<O: Options, L: SizeLimit + 'static> InternalOptions for WithOtherLimit<O, L
|
||||||
type Limit = L;
|
type Limit = L;
|
||||||
type Endian = O::Endian;
|
type Endian = O::Endian;
|
||||||
type IntEncoding = O::IntEncoding;
|
type IntEncoding = O::IntEncoding;
|
||||||
|
type Trailing = O::Trailing;
|
||||||
fn limit(&mut self) -> &mut L {
|
fn limit(&mut self) -> &mut L {
|
||||||
&mut self.new_limit
|
&mut self.new_limit
|
||||||
}
|
}
|
||||||
|
|
@ -284,6 +314,18 @@ impl<O: Options, I: IntEncoding + 'static> InternalOptions for WithOtherIntEncod
|
||||||
type Limit = O::Limit;
|
type Limit = O::Limit;
|
||||||
type Endian = O::Endian;
|
type Endian = O::Endian;
|
||||||
type IntEncoding = I;
|
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 {
|
fn limit(&mut self) -> &mut O::Limit {
|
||||||
self.options.limit()
|
self.options.limit()
|
||||||
|
|
@ -297,6 +339,7 @@ mod internal {
|
||||||
type Limit: SizeLimit + 'static;
|
type Limit: SizeLimit + 'static;
|
||||||
type Endian: BincodeByteOrder + 'static;
|
type Endian: BincodeByteOrder + 'static;
|
||||||
type IntEncoding: IntEncoding + 'static;
|
type IntEncoding: IntEncoding + 'static;
|
||||||
|
type Trailing: TrailingBytes + 'static;
|
||||||
|
|
||||||
fn limit(&mut self) -> &mut Self::Limit;
|
fn limit(&mut self) -> &mut Self::Limit;
|
||||||
}
|
}
|
||||||
|
|
@ -305,6 +348,7 @@ mod internal {
|
||||||
type Limit = O::Limit;
|
type Limit = O::Limit;
|
||||||
type Endian = O::Endian;
|
type Endian = O::Endian;
|
||||||
type IntEncoding = O::IntEncoding;
|
type IntEncoding = O::IntEncoding;
|
||||||
|
type Trailing = O::Trailing;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn limit(&mut self) -> &mut Self::Limit {
|
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();
|
/// let bytes_read = d.bytes_read();
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Deserializer<R, O: Options> {
|
pub struct Deserializer<R, O: Options> {
|
||||||
reader: R,
|
pub(crate) reader: R,
|
||||||
options: O,
|
options: O,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,10 @@ impl<'storage> SliceReader<'storage> {
|
||||||
self.slice = remaining;
|
self.slice = remaining;
|
||||||
Ok(read_slice)
|
Ok(read_slice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_finished(&self) -> bool {
|
||||||
|
self.slice.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> IoReader<R> {
|
impl<R> IoReader<R> {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use serde;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use config::{Infinite, InternalOptions, Options, SizeLimit};
|
use config::{Infinite, InternalOptions, Options, SizeLimit, TrailingBytes};
|
||||||
use de::read::BincodeRead;
|
use de::read::BincodeRead;
|
||||||
use Result;
|
use Result;
|
||||||
|
|
||||||
|
|
@ -111,7 +111,14 @@ where
|
||||||
T: serde::de::DeserializeSeed<'a>,
|
T: serde::de::DeserializeSeed<'a>,
|
||||||
O: InternalOptions,
|
O: InternalOptions,
|
||||||
{
|
{
|
||||||
let reader = ::de::read::SliceReader::new(bytes);
|
|
||||||
let options = ::config::WithOtherLimit::new(options, Infinite);
|
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()
|
DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.serialize(value)
|
.serialize(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,6 +108,7 @@ where
|
||||||
{
|
{
|
||||||
DefaultOptions::new()
|
DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.deserialize_from(reader)
|
.deserialize_from(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,6 +124,7 @@ where
|
||||||
{
|
{
|
||||||
DefaultOptions::new()
|
DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.deserialize_from_custom(reader)
|
.deserialize_from_custom(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,6 +139,7 @@ where
|
||||||
{
|
{
|
||||||
DefaultOptions::new()
|
DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.deserialize_in_place(reader, place)
|
.deserialize_in_place(reader, place)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,6 +150,7 @@ where
|
||||||
{
|
{
|
||||||
DefaultOptions::new()
|
DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.deserialize(bytes)
|
.deserialize(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,5 +161,6 @@ where
|
||||||
{
|
{
|
||||||
DefaultOptions::new()
|
DefaultOptions::new()
|
||||||
.with_fixint_encoding()
|
.with_fixint_encoding()
|
||||||
|
.allow_trailing_bytes()
|
||||||
.serialized_size(value)
|
.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]
|
#[test]
|
||||||
fn too_big_deserialize() {
|
fn too_big_deserialize() {
|
||||||
let serialized = vec![0, 0, 0, 3];
|
let serialized = vec![0, 0, 0, 3];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue