Skip to content

Commit

Permalink
fix: should validate when parsing into lazyvalue
Browse files Browse the repository at this point in the history
  • Loading branch information
liuq19 committed Dec 19, 2024
1 parent 16e4cc2 commit f2806e9
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 14 deletions.
1 change: 1 addition & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ faststr = "0.2"
libfuzzer-sys = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["float_roundtrip"] }
simdutf8 = "0.1"
sonic-rs = { path = ".." }

[[bin]]
Expand Down
19 changes: 16 additions & 3 deletions fuzz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,22 @@ pub fn sonic_rs_fuzz_data(data: &[u8]) {
}
}
}
Err(_) => {
let _ = from_slice::<Value>(data)
.expect_err(&format!("parse invalid json {:?} failed", data));
Err(e) => {
let _ = from_slice::<Value>(data).expect_err(&format!(
"parse invalid json {:?} failed, should return error {e} ",
data
));

// LazyValue should return error if the json is invalid
let msg = e.to_string();
if (msg.starts_with("expected ") || msg.starts_with("EOF"))
&& simdutf8::basic::from_utf8(data).is_ok()
{
let _ = from_slice::<OwnedLazyValue>(data).expect_err(&format!(
"parse invalid json {:?} failed, should return error {msg}",
data
));
}
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/lazyvalue/owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,4 +890,21 @@ mod test {
assert_eq!(to_string(&root).unwrap(), to_string(&root2).unwrap());
assert_eq!(to_string(&root).unwrap(), to_string(&root3).unwrap());
}

#[test]
fn test_owned_from_invalid() {
for json in [
r#"",
r#"{"a":"#,
r#"{"a":123"#,
r#"{"a":}"#,
r#"{"a": x}"#,
r#"{"a":1.}"#,
r#"{"a:1.}"#,
r#"{"a" 1}"#,
r#"{"a"[1}}"#,
] {
crate::from_str::<OwnedLazyValue>(json).expect_err(json);
}
}
}
26 changes: 16 additions & 10 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,28 +581,34 @@ where
#[inline(always)]
pub(crate) fn get_owned_lazyvalue(&mut self, strict: bool) -> Result<OwnedLazyValue> {
let c = self.skip_space();
let start = self.read.index() - 1;
match c {
Some(b'"') => match self.skip_string()? {
ParseStatus::None => {
let slice = self.read.slice_unchecked(start, self.read.index());
let raw = unsafe { self.read.slice_ref(slice).as_faststr() };
return Ok(OwnedLazyValue::from_non_esc_str(raw));
let start = match c {
Some(b'"') => {
let start = self.read.index() - 1;
match self.skip_string()? {
ParseStatus::None => {
let slice = self.read.slice_unchecked(start, self.read.index());
let raw = unsafe { self.read.slice_ref(slice).as_faststr() };
return Ok(OwnedLazyValue::from_non_esc_str(raw));
}
ParseStatus::HasEscaped => {}
}
ParseStatus::HasEscaped => {}
},
start
}
Some(b't') if self.match_literal("rue")? => return Ok(true.into()),
Some(b'f') if self.match_literal("alse")? => return Ok(false.into()),
Some(b'n') if self.match_literal("ull")? => return Ok(().into()),
None => return perr!(self, EofWhileParsing),
_ => {
let start = self.read.index() - 1;
self.read.backward(1);
if strict {
self.skip_one()?;
} else {
self.skip_one_unchecked()?;
}
start
}
}
};
let end = self.read.index();
let sub = self.read.slice_unchecked(start, end);
let raw = unsafe { self.read.slice_ref(sub).as_faststr() };
Expand Down
2 changes: 1 addition & 1 deletion src/serde/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ impl<'de, R: Reader<'de>> Deserializer<R> {
where
V: de::Visitor<'de>,
{
let val = ManuallyDrop::new(self.parser.get_owned_lazyvalue(false)?);
let val = ManuallyDrop::new(self.parser.get_owned_lazyvalue(true)?);
// #Safety
// the json is validate before parsing json, and we pass the document using visit_bytes
// here.
Expand Down

0 comments on commit f2806e9

Please sign in to comment.