Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions rmp-serde/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub enum Error {
/// Uncategorized error.
Uncategorized(String),
Syntax(String),
DepthLimitExceeded,
}

impl ::std::error::Error for Error {
Expand All @@ -44,6 +45,7 @@ impl ::std::error::Error for Error {
LengthMismatch(_) => None,
Uncategorized(_) => None,
Syntax(_) => None,
DepthLimitExceeded => None,
}
}
}
Expand Down Expand Up @@ -171,18 +173,39 @@ pub struct Deserializer<R: Read> {
rd: R,
buf: Vec<u8>,
decoding_option: bool,
depth: usize,
}

macro_rules! depth_count(
( $counter:expr, $expr:expr ) => {
{
$counter -= 1;
if $counter == 0 {
return Err(Error::DepthLimitExceeded)
}
let res = $expr;
$counter += 1;
res
}
}
);

impl<R: Read> Deserializer<R> {
// TODO: Docs.
pub fn new(rd: R) -> Deserializer<R> {
Deserializer {
rd: rd,
buf: Vec::new(),
decoding_option: false,
depth: 1000,
}
}

/// Changes the maximum nesting depth that is allowed
pub fn set_max_depth(&mut self, depth: usize) {
self.depth = depth;
}

/// Gets a reference to the underlying reader in this decoder.
pub fn get_ref(&self) -> &R {
&self.rd
Expand All @@ -209,21 +232,21 @@ impl<R: Read> Deserializer<R> {
fn read_array<V>(&mut self, len: u32, mut visitor: V) -> Result<V::Value>
where V: serde::de::Visitor
{
visitor.visit_seq(SeqVisitor {
depth_count!(self.depth, visitor.visit_seq(SeqVisitor {
deserializer: self,
len: len,
actual: len,
})
}))
}

fn read_map<V>(&mut self, len: u32, mut visitor: V) -> Result<V::Value>
where V: serde::de::Visitor
{
visitor.visit_map(MapVisitor {
depth_count!(self.depth, visitor.visit_map(MapVisitor {
deserializer: self,
len: len,
actual: len,
})
}))
}

fn read_bin_data<V>(&mut self, len: usize, mut visitor: V) -> Result<V::Value>
Expand Down Expand Up @@ -339,7 +362,7 @@ impl<R: Read> serde::Deserializer for Deserializer<R> {
{
// Primarily try to read optimisticly.
self.decoding_option = true;
let res = match visitor.visit_some(self) {
let res = match depth_count!(self.depth, visitor.visit_some(self)) {
Ok(val) => Ok(val),
Err(Error::TypeMismatch(Marker::Null)) => visitor.visit_none(),
Err(err) => Err(err)
Expand All @@ -355,7 +378,7 @@ impl<R: Read> serde::Deserializer for Deserializer<R> {
let len = try!(read_array_size(&mut self.rd));

match len {
2 => visitor.visit(VariantVisitor::new(self)),
2 => depth_count!(self.depth, visitor.visit(VariantVisitor::new(self))),
n => Err(Error::LengthMismatch(n as u32)),
}
}
Expand Down
39 changes: 34 additions & 5 deletions rmp-serde/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub enum Error {

/// Failed to serialize struct, sequence or map, because its length is unknown.
UnknownLength,

/// Depth limit exceeded
DepthLimitExceeded
}

impl ::std::error::Error for Error {
Expand All @@ -36,6 +39,7 @@ impl ::std::error::Error for Error {
Error::InvalidFixedValueWrite(..) => "invalid fixed value write",
Error::InvalidValueWrite(..) => "invalid value write",
Error::UnknownLength => "attempt to serialize struct, sequence or map with unknown length",
Error::DepthLimitExceeded => "depth limit exceeded",
}
}

Expand All @@ -44,6 +48,7 @@ impl ::std::error::Error for Error {
Error::InvalidFixedValueWrite(ref err) => Some(err),
Error::InvalidValueWrite(ref err) => Some(err),
Error::UnknownLength => None,
Error::DepthLimitExceeded => None,
}
}
}
Expand Down Expand Up @@ -108,14 +113,37 @@ impl VariantWriter for StructArrayWriter {
pub struct Serializer<'a, W: VariantWriter> {
wr: &'a mut Write,
vw: W,
depth: usize,
}

impl<'a, W: VariantWriter> Serializer<'a, W> {
/// Changes the maximum nesting depth that is allowed
pub fn set_max_depth(&mut self, depth: usize) {
self.depth = depth;
}
}

macro_rules! depth_count(
( $counter:expr, $expr:expr ) => {
{
$counter -= 1;
if $counter == 0 {
return Err(Error::DepthLimitExceeded)
}
let res = $expr;
$counter += 1;
res
}
}
);

impl<'a> Serializer<'a, StructArrayWriter> {
/// Creates a new MessagePack encoder whose output will be written to the writer specified.
pub fn new(wr: &'a mut Write) -> Serializer<'a, StructArrayWriter> {
Serializer {
wr: wr,
vw: StructArrayWriter,
depth: 1000,
}
}
}
Expand All @@ -126,6 +154,7 @@ impl<'a, W: VariantWriter> Serializer<'a, W> {
Serializer {
wr: wr,
vw: vw,
depth: 1000,
}
}
}
Expand Down Expand Up @@ -245,7 +274,7 @@ impl<'a, W: VariantWriter> serde::Serializer for Serializer<'a, W> {
// ... and its arguments length.
try!(write_array_len(&mut self.wr, len as u32));

while let Some(()) = try!(visitor.visit(self)) { }
while let Some(()) = try!(depth_count!(self.depth, visitor.visit(self))) { }

Ok(())
}
Expand All @@ -267,7 +296,7 @@ impl<'a, W: VariantWriter> serde::Serializer for Serializer<'a, W> {
fn visit_some<T>(&mut self, v: T) -> Result<(), Error>
where T: serde::Serialize,
{
v.serialize(self)
depth_count!(self.depth, v.serialize(self))
}

// TODO: Check len, overflow is possible.
Expand All @@ -281,7 +310,7 @@ impl<'a, W: VariantWriter> serde::Serializer for Serializer<'a, W> {

try!(write_array_len(&mut self.wr, len as u32));

while let Some(()) = try!(visitor.visit(self)) { }
while let Some(()) = try!(depth_count!(self.depth, visitor.visit(self))) { }

Ok(())
}
Expand All @@ -302,7 +331,7 @@ impl<'a, W: VariantWriter> serde::Serializer for Serializer<'a, W> {

try!(write_map_len(&mut self.wr, len as u32));

while let Some(()) = try!(visitor.visit(self)) { }
while let Some(()) = try!(depth_count!(self.depth, visitor.visit(self))) { }

Ok(())
}
Expand Down Expand Up @@ -331,7 +360,7 @@ impl<'a, W: VariantWriter> serde::Serializer for Serializer<'a, W> {

try!(self.vw.write_struct_len(&mut self.wr, len as u32));

while let Some(()) = try!(visitor.visit(self)) { }
while let Some(()) = try!(depth_count!(self.depth, visitor.visit(self))) { }

Ok(())
}
Expand Down