Repository: 3Hren/msgpack-rust (rust)

Issue:
rmpv read_value has no depth limit
I am using `rmpv::decode::read_value` to do some parsing and am running into stack overflows from this crate when fuzz testing my code:

```
# ...snip...
    #186 0x103c9be86 in rmpv::decode::value::read_value::h598f53b10a56f428+0x1596 (packet:x86_64+0x100086e86)
    #187 0x103ca380b in rmpv::decode::value::read_array_data::h9144944be4d4fde4+0x20b (packet:x86_64+0x10008e80b)
    #188 0x103c9be86 in rmpv::decode::value::read_value::h598f53b10a56f428+0x1596 (packet:x86_64+0x100086e86)
    #189 0x103ca380b in rmpv::decode::value::read_array_data::h9144944be4d4fde4+0x20b (packet:x86_64+0x10008e80b)
    #190 0x103c9be86 in rmpv::decode::value::read_value::h598f53b10a56f428+0x1596 (packet:x86_64+0x100086e86)
    #191 0x103ca380b in rmpv::decode::value::read_array_data::h9144944be4d4fde4+0x20b (packet:x86_64+0x10008e80b)
    #192 0x103c9be86 in rmpv::decode::value::read_value::h598f53b10a56f428+0x1596 (packet:x86_64+0x100086e86)
    #193 0x103ca380b in rmpv::decode::value::read_array_data::h9144944be4d4fde4+0x20b (packet:x86_64+0x10008e80b)
# ...snip...
```

Pull request:
fix: add stack depth checking to rmpv
This should resolve #281.

The constant `MAX_DEPTH` came from running `cargo test` on the computer I developed this on. `256` was the largest power of 2 that did not cause a stack overflow, so that seemed good enough. This should allow at least 100 nested structures, if I figure correctly.

Let me know if there is anything to fix, add, or remove.

Patch:
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index d04d0d1..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-sudo: false
-language: rust
-
-addons:
-  apt:
-    packages:
-      - libcurl4-openssl-dev
-      - libelf-dev
-      - libdw-dev
-      - binutils-dev
-      - cmake
-    sources:
-      - kalakris-cmake
-
-rust:
-  - nightly
-  - stable
-  - 1.34.2
-
-before_script:
-  - |
-      if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then
-        cargo install -f cargo-travis;
-        export PATH=$HOME/.cargo/bin:$PATH;
-      fi
-
-script:
-  - |
-      cargo test --all --verbose;
-      if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then
-        cargo bench
-      fi
-
-after_success:
-  - |
-      if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then
-        cargo coveralls --all;
-      fi
-
diff --git a/rmpv/src/decode/mod.rs b/rmpv/src/decode/mod.rs
index 35651c3..6f25d2a 100644
--- a/rmpv/src/decode/mod.rs
+++ b/rmpv/src/decode/mod.rs
@@ -7,8 +7,11 @@ use rmp::decode::{MarkerReadError, ValueReadError};
 pub mod value;
 pub mod value_ref;
 
-pub use self::value::read_value;
-pub use self::value_ref::read_value_ref;
+pub use self::value::{read_value, read_value_with_max_depth};
+pub use self::value_ref::{read_value_ref, read_value_ref_with_max_depth};
+
+/// The maximum recursion depth before [`Error::DepthLimitExceeded`] is returned.
+pub const MAX_DEPTH: usize = 1024;
 
 /// This type represents all possible errors that can occur when deserializing a value.
 #[derive(Debug)]
@@ -17,6 +20,16 @@ pub enum Error {
     InvalidMarkerRead(io::Error),
     /// Error while reading data.
     InvalidDataRead(io::Error),
+    /// The depth limit [`MAX_DEPTH`] was exceeded.
+    DepthLimitExceeded,
+}
+
+fn decrement_depth(depth: usize) -> Result<usize, Error> {
+    if depth == 0 {
+        Err(Error::DepthLimitExceeded)
+    } else {
+        Ok(depth - 1)
+    }
 }
 
 impl Error {
@@ -25,6 +38,7 @@ impl Error {
         match *self {
             Error::InvalidMarkerRead(ref err) => err.kind(),
             Error::InvalidDataRead(ref err) => err.kind(),
+            Error::DepthLimitExceeded => ErrorKind::Unsupported,
         }
     }
 }
@@ -35,6 +49,7 @@ impl error::Error for Error {
         match *self {
             Error::InvalidMarkerRead(ref err) => Some(err),
             Error::InvalidDataRead(ref err) => Some(err),
+            Error::DepthLimitExceeded => None,
         }
     }
 }
@@ -49,6 +64,9 @@ impl Display for Error {
             Error::InvalidDataRead(ref err) => {
                 write!(fmt, "I/O error while reading non-marker bytes: {}", err)
             }
+            Error::DepthLimitExceeded => {
+                write!(fmt, "depth limit exceeded")
+            }
         }
     }
 }
@@ -79,6 +97,7 @@ impl Into<io::Error> for Error {
         match self {
             Error::InvalidMarkerRead(err) |
             Error::InvalidDataRead(err) => err,
+            Error::DepthLimitExceeded => io::Error::new(self.kind(), self),
         }
     }
 }
diff --git a/rmpv/src/decode/value.rs b/rmpv/src/decode/value.rs
index d9620e1..1d773f5 100644
--- a/rmpv/src/decode/value.rs
+++ b/rmpv/src/decode/value.rs
@@ -14,34 +14,40 @@ use super::Error;
 const PREALLOC_MAX: usize = 64 * 1024; // 64 KiB
 
 
-fn read_array_data<R: Read>(rd: &mut R, mut len: usize) -> Result<Vec<Value>, Error> {
+fn read_array_data<R: Read>(rd: &mut R, mut len: usize, depth: usize) -> Result<Vec<Value>, Error> {
+    let depth = super::decrement_depth(depth)?;
+
     // Note: Do not preallocate a Vec of size `len`.
     // See https://github.com/3Hren/msgpack-rust/issues/151
     let mut vec = Vec::new();
 
     while len > 0 {
-        vec.push(read_value(rd)?);
+        vec.push(read_value_inner(rd, depth)?);
         len -= 1;
     }
 
     Ok(vec)
 }
 
-fn read_map_data<R: Read>(rd: &mut R, mut len: usize) -> Result<Vec<(Value, Value)>, Error> {
+fn read_map_data<R: Read>(rd: &mut R, mut len: usize, depth: usize) -> Result<Vec<(Value, Value)>, Error> {
+    let depth = super::decrement_depth(depth)?;
+
     // Note: Do not preallocate a Vec of size `len`.
     // See https://github.com/3Hren/msgpack-rust/issues/151
     let mut vec = Vec::new();
 
     while len > 0 {
-        vec.push((read_value(rd)?, read_value(rd)?));
+        vec.push((read_value_inner(rd, depth)?, read_value_inner(rd, depth)?));
         len -= 1;
     }
 
     Ok(vec)
 }
 
-fn read_str_data<R: Read>(rd: &mut R, len: usize) -> Result<Utf8String, Error> {
-    match String::from_utf8(read_bin_data(rd, len)?) {
+fn read_str_data<R: Read>(rd: &mut R, len: usize, depth: usize) -> Result<Utf8String, Error> {
+    let depth = super::decrement_depth(depth)?;
+
+    match String::from_utf8(read_bin_data(rd, len, depth)?) {
         Ok(s) => Ok(Utf8String::from(s)),
         Err(err) => {
             let e = err.utf8_error();
@@ -53,7 +59,9 @@ fn read_str_data<R: Read>(rd: &mut R, len: usize) -> Result<Utf8String, Error> {
     }
 }
 
-fn read_bin_data<R: Read>(rd: &mut R, len: usize) -> Result<Vec<u8>, Error> {
+fn read_bin_data<R: Read>(rd: &mut R, len: usize, depth: usize) -> Result<Vec<u8>, Error> {
+    let _depth = super::decrement_depth(depth)?;
+
     let mut buf = Vec::with_capacity(min(len, PREALLOC_MAX));
     let bytes_read = rd.take(len as u64).read_to_end(&mut buf).map_err(Error::InvalidDataRead)?;
     if bytes_read != len {
@@ -66,24 +74,17 @@ fn read_bin_data<R: Read>(rd: &mut R, len: usize) -> Result<Vec<u8>, Error> {
     Ok(buf)
 }
 
-fn read_ext_body<R: Read>(rd: &mut R, len: usize) -> Result<(i8, Vec<u8>), Error> {
+fn read_ext_body<R: Read>(rd: &mut R, len: usize, depth: usize) -> Result<(i8, Vec<u8>), Error> {
+    let depth = super::decrement_depth(depth)?;
+
     let ty = read_data_i8(rd)?;
-    let vec = read_bin_data(rd, len)?;
+    let vec = read_bin_data(rd, len, depth)?;
 
     Ok((ty, vec))
 }
 
-/// Attempts to read bytes from the given reader and interpret them as a `Value`.
-///
-/// # Errors
-///
-/// This function will return `Error` on any I/O error while either reading or decoding a `Value`.
-/// All instances of `ErrorKind::Interrupted` are handled by this function and the underlying
-/// operation is retried.
-#[inline(never)]
-pub fn read_value<R>(rd: &mut R) -> Result<Value, Error>
-    where R: Read
-{
+fn read_value_inner<R>(rd: &mut R, depth: usize) -> Result<Value, Error> where R: Read {
+    let depth = super::decrement_depth(depth)?;
     let val = match read_marker(rd)? {
         Marker::Null => Value::Nil,
         Marker::True => Value::Boolean(true),
@@ -101,105 +102,105 @@ pub fn read_value<R>(rd: &mut R) -> Result<Value, Error>
         Marker::F32 => Value::F32(read_data_f32(rd)?),
         Marker::F64 => Value::F64(read_data_f64(rd)?),
         Marker::FixStr(len) => {
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             Value::String(res)
         }
         Marker::Str8 => {
             let len = read_data_u8(rd)?;
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             Value::String(res)
         }
         Marker::Str16 => {
             let len = read_data_u16(rd)?;
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             Value::String(res)
         }
         Marker::Str32 => {
             let len = read_data_u32(rd)?;
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             Value::String(res)
         }
         Marker::FixArray(len) => {
-            let vec = read_array_data(rd, len as usize)?;
+            let vec = read_array_data(rd, len as usize, depth)?;
             Value::Array(vec)
         }
         Marker::Array16 => {
             let len = read_data_u16(rd)?;
-            let vec = read_array_data(rd, len as usize)?;
+            let vec = read_array_data(rd, len as usize, depth)?;
             Value::Array(vec)
         }
         Marker::Array32 => {
             let len = read_data_u32(rd)?;
-            let vec = read_array_data(rd, len as usize)?;
+            let vec = read_array_data(rd, len as usize, depth)?;
             Value::Array(vec)
         }
         Marker::FixMap(len) => {
-            let map = read_map_data(rd, len as usize)?;
+            let map = read_map_data(rd, len as usize, depth)?;
             Value::Map(map)
         }
         Marker::Map16 => {
             let len = read_data_u16(rd)?;
-            let map = read_map_data(rd, len as usize)?;
+            let map = read_map_data(rd, len as usize, depth)?;
             Value::Map(map)
         }
         Marker::Map32 => {
             let len = read_data_u32(rd)?;
-            let map = read_map_data(rd, len as usize)?;
+            let map = read_map_data(rd, len as usize, depth)?;
             Value::Map(map)
         }
         Marker::Bin8 => {
             let len = read_data_u8(rd)?;
-            let vec = read_bin_data(rd, len as usize)?;
+            let vec = read_bin_data(rd, len as usize, depth)?;
             Value::Binary(vec)
         }
         Marker::Bin16 => {
             let len = read_data_u16(rd)?;
-            let vec = read_bin_data(rd, len as usize)?;
+            let vec = read_bin_data(rd, len as usize, depth)?;
             Value::Binary(vec)
         }
         Marker::Bin32 => {
             let len = read_data_u32(rd)?;
-            let vec = read_bin_data(rd, len as usize)?;
+            let vec = read_bin_data(rd, len as usize, depth)?;
             Value::Binary(vec)
         }
         Marker::FixExt1 => {
             let len = 1 as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::FixExt2 => {
             let len = 2 as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::FixExt4 => {
             let len = 4 as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::FixExt8 => {
             let len = 8 as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::FixExt16 => {
             let len = 16 as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::Ext8 => {
             let len = read_data_u8(rd)? as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::Ext16 => {
             let len = read_data_u16(rd)? as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::Ext32 => {
             let len = read_data_u32(rd)? as usize;
-            let (ty, vec) = read_ext_body(rd, len)?;
+            let (ty, vec) = read_ext_body(rd, len, depth)?;
             Value::Ext(ty, vec)
         }
         Marker::Reserved => Value::Nil,
@@ -207,3 +208,39 @@ pub fn read_value<R>(rd: &mut R) -> Result<Value, Error>
 
     Ok(val)
 }
+
+/// Attempts to read bytes from the given reader and interpret them as a [`Value`].
+///
+/// # Errors
+///
+/// This function will return [`Error`] on any I/O error while either reading or decoding a [`Value`].
+/// All instances of [`ErrorKind::Interrupted`](io::ErrorKind) are handled by this function and the
+/// underlying operation is retried.
+///
+/// [`Error::DepthLimitExceeded`] is returned if this function recurses
+/// [`MAX_DEPTH`](super::MAX_DEPTH) times. To configure the maximum recursion depth, use
+/// [`read_value_with_max_depth`] instead.
+#[inline(never)]
+pub fn read_value<R>(rd: &mut R) -> Result<Value, Error>
+    where R: Read
+{
+    read_value_inner(rd, super::MAX_DEPTH)
+}
+
+/// Attempts to read bytes from the given reader and interpret them as a [`Value`].
+///
+/// # Errors
+///
+/// This function will return [`Error`] on any I/O error while either reading or decoding a [`Value`].
+/// All instances of [`ErrorKind::Interrupted`](io::ErrorKind) are handled by this function and the
+/// underlying operation is retried.
+///
+/// [`Error::DepthLimitExceeded`] is returned if this function recurses
+/// `max_depth` times. If the default [`MAX_DEPTH`](super::MAX_DEPTH) is sufficient or you do not
+/// need recursion depth checking for your data, consider using [`read_value`] instead.
+#[inline(never)]
+pub fn read_value_with_max_depth<R>(rd: &mut R, max_depth: usize) -> Result<Value, Error>
+    where R: Read
+{
+    read_value_inner(rd, max_depth)   
+}
diff --git a/rmpv/src/decode/value_ref.rs b/rmpv/src/decode/value_ref.rs
index aae2732..ad98c00 100644
--- a/rmpv/src/decode/value_ref.rs
+++ b/rmpv/src/decode/value_ref.rs
@@ -10,10 +10,11 @@ use rmp::decode::{read_marker, read_data_u8, read_data_u16, read_data_u32, read_
 use crate::{Utf8StringRef, ValueRef};
 use super::Error;
 
-fn read_str_data<'a, R>(rd: &mut R, len: usize) -> Result<Utf8StringRef<'a>, Error>
+fn read_str_data<'a, R>(rd: &mut R, len: usize, depth: usize) -> Result<Utf8StringRef<'a>, Error>
     where R: BorrowRead<'a>
 {
-    let buf = read_bin_data(rd, len)?;
+    let depth = super::decrement_depth(depth)?;
+    let buf = read_bin_data(rd, len, depth)?;
     match str::from_utf8(buf) {
         Ok(s) => Ok(Utf8StringRef::from(s)),
         Err(err) => {
@@ -25,9 +26,10 @@ fn read_str_data<'a, R>(rd: &mut R, len: usize) -> Result<Utf8StringRef<'a>, Err
     }
 }
 
-fn read_bin_data<'a, R>(rd: &mut R, len: usize) -> Result<&'a [u8], Error>
+fn read_bin_data<'a, R>(rd: &mut R, len: usize, depth: usize) -> Result<&'a [u8], Error>
     where R: BorrowRead<'a>
 {
+    let _depth = super::decrement_depth(depth)?;
     let buf = rd.fill_buf();
 
     if len > buf.len() {
@@ -41,39 +43,42 @@ fn read_bin_data<'a, R>(rd: &mut R, len: usize) -> Result<&'a [u8], Error>
     Ok(buf)
 }
 
-fn read_ext_body<'a, R>(rd: &mut R, len: usize) -> Result<(i8, &'a [u8]), Error>
+fn read_ext_body<'a, R>(rd: &mut R, len: usize, depth: usize) -> Result<(i8, &'a [u8]), Error>
     where R: BorrowRead<'a>
 {
+    let depth = super::decrement_depth(depth)?;
     let ty = read_data_i8(rd)?;
-    let buf = read_bin_data(rd, len)?;
+    let buf = read_bin_data(rd, len, depth)?;
 
     Ok((ty, buf))
 }
 
-fn read_array_data<'a, R>(rd: &mut R, mut len: usize) -> Result<Vec<ValueRef<'a>>, Error>
+fn read_array_data<'a, R>(rd: &mut R, mut len: usize, depth: usize) -> Result<Vec<ValueRef<'a>>, Error>
     where R: BorrowRead<'a>
 {
+    let depth = super::decrement_depth(depth)?;
     // Note: Do not preallocate a Vec of size `len`.
     // See https://github.com/3Hren/msgpack-rust/issues/151
     let mut vec = Vec::new();
 
     while len > 0 {
-        vec.push(read_value_ref(rd)?);
+        vec.push(read_value_ref_inner(rd, depth)?);
         len -= 1;
     }
 
     Ok(vec)
 }
 
-fn read_map_data<'a, R>(rd: &mut R, mut len: usize) -> Result<Vec<(ValueRef<'a>, ValueRef<'a>)>, Error>
+fn read_map_data<'a, R>(rd: &mut R, mut len: usize, depth: usize) -> Result<Vec<(ValueRef<'a>, ValueRef<'a>)>, Error>
     where R: BorrowRead<'a>
 {
+    let depth = super::decrement_depth(depth)?;
     // Note: Do not preallocate a Vec of size `len`.
     // See https://github.com/3Hren/msgpack-rust/issues/151
     let mut vec = Vec::new();
 
     while len > 0 {
-        vec.push((read_value_ref(rd)?, read_value_ref(rd)?));
+        vec.push((read_value_ref_inner(rd, depth)?, read_value_ref_inner(rd, depth)?));
         len -= 1;
     }
 
@@ -124,40 +129,10 @@ impl<'a> BorrowRead<'a> for Cursor<&'a [u8]> {
     }
 }
 
-/// Attempts to read the data from the given reader until either a complete MessagePack value
-/// decoded or an error detected.
-///
-/// Returns either a non-owning `ValueRef`, which borrows the buffer from the given reader or an
-/// error.
-///
-/// The reader should meet the requirement of a special `BorrowRead` trait, which allows to mutate
-/// itself but permits to mutate the buffer it contains. It allows to perform a completely
-/// zero-copy reading without a data loss fear in case of an error.
-///
-/// Currently only two types fit in this requirement: `&[u8]` and `Cursor<&[u8]>`. Using Cursor is
-/// helpful, when you need to know how exactly many bytes the decoded ValueRef consumes. A `Vec<u8>`
-/// type doesn't fit in the `BorrowRead` requirement, because its mut reference can mutate the
-/// underlying buffer - use `Vec::as_slice()` if you need to decode a value from the vector.
-///
-/// # Errors
-///
-/// Returns an `Error` value if unable to continue the decoding operation either because of read
-/// failure or any other circumstances. See `Error` documentation for more information.
-///
-/// # Examples
-/// ```
-/// use rmpv::ValueRef;
-/// use rmpv::decode::read_value_ref;
-///
-/// let buf = [0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
-/// let mut rd = &buf[..];
-///
-/// assert_eq!(ValueRef::from("le message"), read_value_ref(&mut rd).unwrap());
-/// ```
-#[inline(never)]
-pub fn read_value_ref<'a, R>(rd: &mut R) -> Result<ValueRef<'a>, Error>
+fn read_value_ref_inner<'a, R>(rd: &mut R, depth: usize) -> Result<ValueRef<'a>, Error>
     where R: BorrowRead<'a>
 {
+    let depth = super::decrement_depth(depth)?;
 
     // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
     // 1 byte from the `rd`.
@@ -178,105 +153,105 @@ pub fn read_value_ref<'a, R>(rd: &mut R) -> Result<ValueRef<'a>, Error>
         Marker::F32 => ValueRef::F32(read_data_f32(rd)?),
         Marker::F64 => ValueRef::F64(read_data_f64(rd)?),
         Marker::FixStr(len) => {
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             ValueRef::String(res)
         }
         Marker::Str8 => {
             let len = read_data_u8(rd)?;
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             ValueRef::String(res)
         }
         Marker::Str16 => {
             let len = read_data_u16(rd)?;
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             ValueRef::String(res)
         }
         Marker::Str32 => {
             let len = read_data_u32(rd)?;
-            let res = read_str_data(rd, len as usize)?;
+            let res = read_str_data(rd, len as usize, depth)?;
             ValueRef::String(res)
         }
         Marker::Bin8 => {
             let len = read_data_u8(rd)?;
-            let res = read_bin_data(rd, len as usize)?;
+            let res = read_bin_data(rd, len as usize, depth)?;
             ValueRef::Binary(res)
         }
         Marker::Bin16 => {
             let len = read_data_u16(rd)?;
-            let res = read_bin_data(rd, len as usize)?;
+            let res = read_bin_data(rd, len as usize, depth)?;
             ValueRef::Binary(res)
         }
         Marker::Bin32 => {
             let len = read_data_u32(rd)?;
-            let res = read_bin_data(rd, len as usize)?;
+            let res = read_bin_data(rd, len as usize, depth)?;
             ValueRef::Binary(res)
         }
         Marker::FixArray(len) => {
-            let vec = read_array_data(rd, len as usize)?;
+            let vec = read_array_data(rd, len as usize, depth)?;
             ValueRef::Array(vec)
         }
         Marker::Array16 => {
             let len = read_data_u16(rd)?;
-            let vec = read_array_data(rd, len as usize)?;
+            let vec = read_array_data(rd, len as usize, depth)?;
             ValueRef::Array(vec)
         }
         Marker::Array32 => {
             let len = read_data_u32(rd)?;
-            let vec = read_array_data(rd, len as usize)?;
+            let vec = read_array_data(rd, len as usize, depth)?;
             ValueRef::Array(vec)
         }
         Marker::FixMap(len) => {
-            let map = read_map_data(rd, len as usize)?;
+            let map = read_map_data(rd, len as usize, depth)?;
             ValueRef::Map(map)
         }
         Marker::Map16 => {
             let len = read_data_u16(rd)?;
-            let map = read_map_data(rd, len as usize)?;
+            let map = read_map_data(rd, len as usize, depth)?;
             ValueRef::Map(map)
         }
         Marker::Map32 => {
             let len = read_data_u32(rd)?;
-            let map = read_map_data(rd, len as usize)?;
+            let map = read_map_data(rd, len as usize, depth)?;
             ValueRef::Map(map)
         }
         Marker::FixExt1 => {
             let len = 1;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::FixExt2 => {
             let len = 2;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::FixExt4 => {
             let len = 4;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::FixExt8 => {
             let len = 8;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::FixExt16 => {
             let len = 16;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::Ext8 => {
             let len = read_data_u8(rd)?;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::Ext16 => {
             let len = read_data_u16(rd)?;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::Ext32 => {
             let len = read_data_u32(rd)?;
-            let (ty, vec) = read_ext_body(rd, len as usize)?;
+            let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
             ValueRef::Ext(ty, vec)
         }
         Marker::Reserved => ValueRef::Nil,
@@ -284,3 +259,64 @@ pub fn read_value_ref<'a, R>(rd: &mut R) -> Result<ValueRef<'a>, Error>
 
     Ok(val)
 }
+
+/// Attempts to read the data from the given reader until either a complete MessagePack value
+/// decoded or an error detected.
+///
+/// Returns either a non-owning `ValueRef`, which borrows the buffer from the given reader or an
+/// error.
+///
+/// The reader should meet the requirement of a special `BorrowRead` trait, which allows to mutate
+/// itself but permits to mutate the buffer it contains. It allows to perform a completely
+/// zero-copy reading without a data loss fear in case of an error.
+///
+/// Currently only two types fit in this requirement: `&[u8]` and `Cursor<&[u8]>`. Using Cursor is
+/// helpful, when you need to know how exactly many bytes the decoded ValueRef consumes. A `Vec<u8>`
+/// type doesn't fit in the `BorrowRead` requirement, because its mut reference can mutate the
+/// underlying buffer - use `Vec::as_slice()` if you need to decode a value from the vector.
+///
+/// # Errors
+///
+/// Returns an `Error` value if unable to continue the decoding operation either because of read
+/// failure or any other circumstances. See `Error` documentation for more information.
+///
+/// This function enforces a maximum recursion depth of [`MAX_DEPTH`](super::MAX_DEPTH) and returns
+/// [`Error::DepthLimitExceeded`] if the maximum is hit. If you run into stack overflows despite
+/// this, use [`read_value_ref_with_max_depth`] with a custom maximum depth.
+///
+/// # Examples
+/// ```
+/// use rmpv::ValueRef;
+/// use rmpv::decode::read_value_ref;
+///
+/// let buf = [0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
+/// let mut rd = &buf[..];
+///
+/// assert_eq!(ValueRef::from("le message"), read_value_ref(&mut rd).unwrap());
+/// ```
+#[inline(never)]
+pub fn read_value_ref<'a, R>(rd: &mut R) -> Result<ValueRef<'a>, Error>
+    where R: BorrowRead<'a>
+{
+    read_value_ref_inner(rd, super::MAX_DEPTH)
+}
+
+/// Attempts to read the data from the given reader until either a complete MessagePack value
+/// decoded or an error detected.
+///
+/// Returns either a non-owning `ValueRef`, which borrows the buffer from the given reader or an
+/// error.
+///
+/// See [`read_value_ref`] for more information on how to use this function. This variant allows
+/// you to specify the maximum recursion depth, if [`MAX_DEPTH`](super::MAX_DEPTH) is too high.
+///
+/// # Errors
+///
+/// Same as [`read_value_ref`], using the `max_depth` parameter in place of
+/// [`MAX_DEPTH`](super::MAX_DEPTH).
+#[inline(never)]
+pub fn read_value_ref_with_max_depth<'a, R>(rd: &mut R, max_depth: usize) -> Result<ValueRef<'a>, Error>
+    where R: BorrowRead<'a>
+{
+    read_value_ref_inner(rd, max_depth)
+}


Test patch:
diff --git a/rmpv-tests/tests/decode.rs b/rmpv-tests/tests/decode.rs
index d675b07..b2fce2b 100644
--- a/rmpv-tests/tests/decode.rs
+++ b/rmpv-tests/tests/decode.rs
@@ -20,6 +20,18 @@ fn test_decode(buf: &[u8], v: Value) {
     assert_eq!(v, val1);
 }
 
+#[test]
+fn test_stack_depth_checking() {
+    let mut buf: Vec<u8> = (0..decode::MAX_DEPTH).map(|_| 0x91).collect();
+    buf.push(0xc3);
+
+    match decode::read_value(&mut &buf[..]) {
+        Ok(_) => panic!("expected max stack depth to be exceeded"),
+        Err(decode::Error::DepthLimitExceeded) => {},
+        Err(err) => panic!("unexpected error: {}", err),
+    }
+}
+
 #[test]
 fn pass_null() {
     test_decode(&[0xc0], Value::Nil);