Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: should validate when parsing into lazyvalue #144

Merged
merged 2 commits into from
Dec 19, 2024
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license = "Apache-2.0"
name = "sonic-rs"
readme = "README.md"
repository = "https://github.com/cloudwego/sonic-rs"
version = "0.4.0-rc1"
version = "0.4.0-rc2"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
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
Loading