--- /dev/null +++ b/crates/nixlike/fuzz/.gitignore @@ -0,0 +1,4 @@ + +target +corpus +artifacts --- /dev/null +++ b/crates/nixlike/fuzz/Cargo.lock @@ -0,0 +1,182 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7" + +[[package]] +name = "bumpalo" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" + +[[package]] +name = "cc" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" + +[[package]] +name = "dprint-core" +version = "0.46.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df98b7d98583d9d57311b9df81f571f35a6ca3e8675d0128333b2e923dc85bcd" +dependencies = [ + "bumpalo", + "rustc-hash", + "serde", +] + +[[package]] +name = "libfuzzer-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36a9a84a6e8b55dfefb04235e55edb2b9a2a18488fcae777a6bdaa6f06f1deb3" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "nixlike" +version = "0.1.0" +dependencies = [ + "dprint-core", + "linked-hash-map", + "peg", + "serde", + "thiserror", +] + +[[package]] +name = "nixlike-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "nixlike", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "peg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thiserror" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" --- /dev/null +++ b/crates/nixlike/fuzz/Cargo.toml @@ -0,0 +1,26 @@ + +[package] +name = "nixlike-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2018" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.nixlike] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "fuzz_target_1" +path = "fuzz_targets/fuzz_target_1.rs" +test = false +doc = false --- /dev/null +++ b/crates/nixlike/fuzz/fuzz_targets/fuzz_target_1.rs @@ -0,0 +1,9 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: String| { + let serialized = nixlike::serialize(data.clone()).unwrap(); + let deserialized: String = nixlike::parse_str(&serialized).unwrap(); + + assert_eq!(data, deserialized); +}); --- a/crates/nixlike/src/lib.rs +++ b/crates/nixlike/src/lib.rs @@ -40,6 +40,10 @@ rule string_char() -> &'input str = "\\\"" { "\"" } / "\\\\" { "\\" } + / "\\n" { "\n" } + / "\\t" { "\t" } + / "\\r" { "\r" } + / "''$" { "$" } / c:$([_]) { c } rule string() -> String = quiet! { "\"" v:(!"\"" c:string_char() {c})* "\"" { v.into_iter().collect() } } / expected!("") @@ -47,7 +51,10 @@ = quiet! { "true" {true} / "false" {false} } / expected!("") rule indent() -> String - = quiet! { s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-']+) { s.to_owned() } } / expected!("") + = quiet! { + s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-']+) { s.to_owned() } + / "\"" s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '.']+) "\"" { s.to_owned() } + } / expected!("") rule object() -> LinkedHashMap = "{" _ e:(k:indent()++(_ "." _) _ "=" _ v:value() _ ";" _ {(k, v)})* @@ -111,20 +118,5 @@ #[test] fn test() { - let v: serde_json::Value = parse_str( - r#" - { - b.c = 2; - b.d = "hello"; - c = { - k = 123; - p = 231; - ll = [1 2 3 [] [[4 5 6]] ]; - }; - } - "#, - ) - .unwrap(); - let s: String = serialize(v).unwrap(); - println!("{}", s); + assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\""); } --- a/crates/nixlike/src/to_string.rs +++ b/crates/nixlike/src/to_string.rs @@ -5,7 +5,13 @@ }; fn write_nix_obj_key_buf(k: &str, v: &Value, out: &mut PrintItems) { - out.push_str(k); + if k.contains(".") { + out.push_str("\""); + out.push_str(k); + out.push_str("\""); + } else { + out.push_str(k); + } match v { Value::Object(o) if o.len() == 1 => { let (k, v) = o.iter().next().unwrap(); @@ -26,7 +32,15 @@ Value::Null => out.push_str("null"), Value::Boolean(v) => out.push_str(if *v { "true" } else { "false" }), Value::Number(n) => out.push_str(&format!("{}", n)), - Value::String(s) => out.push_str(&format!("{:?}", s)), + Value::String(s) => out.push_str(&format!( + "\"{}\"", + s.replace('\\', "\\\\") + .replace('"', "\\\"") + .replace('\n', "\\n") + .replace('\t', "\\t") + .replace('\r', "\\r") + .replace("$", "''$") + )), Value::Array(a) => { if a.is_empty() { out.push_str("[ ]");