Skip to content

Commit 3516a90

Browse files
authored
Merge pull request #163 from serde-rs/limit
Limit recursion to 128 levels
2 parents b706bc3 + 4d57ebe commit 3516a90

File tree

2 files changed

+46
-7
lines changed

2 files changed

+46
-7
lines changed

json/src/de.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ impl<Iter> de::Deserializer for Deserializer<Iter>
9494
struct DeserializerImpl<R: Read> {
9595
read: R,
9696
str_buf: Vec<u8>,
97+
remaining_depth: u8,
9798
}
9899

99100
macro_rules! overflow {
@@ -107,6 +108,7 @@ impl<R: Read> DeserializerImpl<R> {
107108
DeserializerImpl {
108109
read: read,
109110
str_buf: Vec::with_capacity(128),
111+
remaining_depth: 128,
110112
}
111113
}
112114

@@ -205,12 +207,30 @@ impl<R: Read> DeserializerImpl<R> {
205207
visitor.visit_str(s)
206208
}
207209
b'[' => {
210+
self.remaining_depth -= 1;
211+
if self.remaining_depth == 0 {
212+
return Err(self.peek_error(stack_overflow()));
213+
}
214+
208215
self.eat_char();
209-
visitor.visit_seq(SeqVisitor::new(self))
216+
let ret = visitor.visit_seq(SeqVisitor::new(self));
217+
218+
self.remaining_depth += 1;
219+
220+
ret
210221
}
211222
b'{' => {
223+
self.remaining_depth -= 1;
224+
if self.remaining_depth == 0 {
225+
return Err(self.peek_error(stack_overflow()));
226+
}
227+
212228
self.eat_char();
213-
visitor.visit_map(MapVisitor::new(self))
229+
let ret = visitor.visit_map(MapVisitor::new(self));
230+
231+
self.remaining_depth += 1;
232+
233+
ret
214234
}
215235
_ => Err(self.peek_error(ErrorCode::ExpectedSomeValue)),
216236
};
@@ -523,6 +543,10 @@ impl<R: Read> DeserializerImpl<R> {
523543
}
524544
}
525545

546+
fn stack_overflow() -> ErrorCode {
547+
ErrorCode::Custom("recursion limit exceeded".into())
548+
}
549+
526550
static POW10: [f64; 309] =
527551
[1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009,
528552
1e010, 1e011, 1e012, 1e013, 1e014, 1e015, 1e016, 1e017, 1e018, 1e019,
@@ -610,12 +634,15 @@ impl<R: Read> de::Deserializer for DeserializerImpl<R> {
610634

611635
match try!(self.peek_or_null()) {
612636
b'{' => {
637+
self.remaining_depth -= 1;
638+
if self.remaining_depth == 0 {
639+
return Err(self.peek_error(stack_overflow()));
640+
}
641+
613642
self.eat_char();
614-
try!(self.parse_whitespace());
643+
let value = try!(visitor.visit(VariantVisitor::new(self)));
615644

616-
let value = {
617-
try!(visitor.visit(VariantVisitor::new(self)))
618-
};
645+
self.remaining_depth += 1;
619646

620647
try!(self.parse_whitespace());
621648

json_tests/tests/test_json.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::f64;
22
use std::fmt::Debug;
33
use std::i64;
4+
use std::iter;
45
use std::marker::PhantomData;
56
use std::u64;
67

@@ -737,7 +738,7 @@ macro_rules! test_parse_err {
737738
}
738739

739740
// FIXME (#5527): these could be merged once UFCS is finished.
740-
fn test_parse_err<T>(errors: Vec<(&'static str, Error)>)
741+
fn test_parse_err<T>(errors: Vec<(&str, Error)>)
741742
where T: Debug + PartialEq + de::Deserialize,
742743
{
743744
for &(s, ref err) in &errors {
@@ -1632,3 +1633,14 @@ fn test_json_pointer() {
16321633
assert!(data.pointer("/foo/00").is_none());
16331634
assert!(data.pointer("/foo/01").is_none());
16341635
}
1636+
1637+
#[test]
1638+
fn test_stack_overflow() {
1639+
let brackets: String = iter::repeat('[').take(127).chain(iter::repeat(']').take(127)).collect();
1640+
let _: Value = serde_json::from_str(&brackets).unwrap();
1641+
1642+
let brackets: String = iter::repeat('[').take(128).collect();
1643+
test_parse_err::<Value>(vec![
1644+
(&brackets, Error::Syntax(ErrorCode::Custom("recursion limit exceeded".into()), 1, 128)),
1645+
]);
1646+
}

0 commit comments

Comments
 (0)