Skip to content

Commit 5382f8d

Browse files
committed
feat(fuzz): add tomlq_fuzz target
Closes #1102 — Fuzz target for the hand-written TOML parser in the tomlq builtin. Tests parsing and dot-path queries on arbitrary TOML documents.
1 parent 527d6fd commit 5382f8d

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

crates/bashkit/fuzz/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ path = "fuzz_targets/envsubst_fuzz.rs"
8787
test = false
8888
doc = false
8989
bench = false
90+
91+
[[bin]]
92+
name = "tomlq_fuzz"
93+
path = "fuzz_targets/tomlq_fuzz.rs"
94+
test = false
95+
doc = false
96+
bench = false
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//! Fuzz target for the tomlq builtin
2+
//!
3+
//! Tests the hand-written TOML parser to find:
4+
//! - Panics on malformed TOML documents
5+
//! - Edge cases with nested tables, inline tables, multiline strings
6+
//! - Incorrect datetime parsing
7+
//! - Memory exhaustion from pathological input
8+
//!
9+
//! Run with: cargo +nightly fuzz run tomlq_fuzz -- -max_total_time=300
10+
11+
#![no_main]
12+
13+
use libfuzzer_sys::fuzz_target;
14+
15+
fuzz_target!(|data: &[u8]| {
16+
// Only process valid UTF-8
17+
if let Ok(input) = std::str::from_utf8(data) {
18+
// Limit input size to prevent OOM
19+
if input.len() > 1024 {
20+
return;
21+
}
22+
23+
// Split input into TOML content and query path
24+
let (toml_doc, query) = match input.find('\n') {
25+
Some(pos) => (&input[..pos], &input[pos + 1..]),
26+
None => (input, "." as &str),
27+
};
28+
29+
// Skip empty documents
30+
if toml_doc.trim().is_empty() {
31+
return;
32+
}
33+
34+
// Reject deeply nested structures
35+
let depth = toml_doc
36+
.bytes()
37+
.filter(|&b| b == b'[' || b == b'{')
38+
.count();
39+
if depth > 20 {
40+
return;
41+
}
42+
43+
let rt = tokio::runtime::Builder::new_current_thread()
44+
.enable_all()
45+
.build()
46+
.unwrap();
47+
48+
rt.block_on(async {
49+
let mut bash = bashkit::Bash::builder()
50+
.limits(
51+
bashkit::ExecutionLimits::new()
52+
.max_commands(50)
53+
.max_subst_depth(3)
54+
.max_stdout_bytes(4096)
55+
.max_stderr_bytes(4096)
56+
.timeout(std::time::Duration::from_millis(200)),
57+
)
58+
.build();
59+
60+
// Test 1: parse TOML and query by path
61+
let script = format!(
62+
"echo '{}' | tomlq '{}' 2>/dev/null; true",
63+
toml_doc.replace('\'', "'\\''"),
64+
query.replace('\'', "'\\''"),
65+
);
66+
let _ = bash.exec(&script).await;
67+
68+
// Test 2: parse TOML with dot-path query
69+
let script2 = format!(
70+
"echo '{}' | tomlq 2>/dev/null; true",
71+
toml_doc.replace('\'', "'\\''"),
72+
);
73+
let _ = bash.exec(&script2).await;
74+
});
75+
}
76+
});

0 commit comments

Comments
 (0)