Skip to main content

probe_parser_rss/
probe_parser_rss.rs

1//! Probe whether `parse_xpath` leaks memory.
2//!
3//! Parses the same input N times and prints RSS at the start, midpoint,
4//! and end.  Flat RSS → no leak (the fuzz OOM was libFuzzer/ASAN
5//! accumulation).  Growing RSS → real leak we need to fix.
6
7use std::time::Instant;
8use sup_xml_core::xpath::parse_xpath;
9
10// Use ps to read RSS — avoids pulling libc as a dep.
11fn rss_bytes() -> u64 {
12    let pid = std::process::id();
13    let out = std::process::Command::new("ps")
14        .args(["-o", "rss=", "-p", &pid.to_string()])
15        .output()
16        .ok();
17    out.and_then(|o| String::from_utf8(o.stdout).ok())
18        .and_then(|s| s.trim().parse::<u64>().ok())
19        .map(|kb| kb * 1024)
20        .unwrap_or(0)
21}
22
23fn main() {
24    let path = std::env::args().nth(1).expect("usage: probe_parser_rss <input-path>");
25    let bytes = std::fs::read(&path).expect("read input");
26    let s = std::str::from_utf8(&bytes).expect("UTF-8");
27    let iters: usize = std::env::args().nth(2)
28        .and_then(|s| s.parse().ok()).unwrap_or(1_000_000);
29
30    println!("input: {} bytes, {} iters", s.len(), iters);
31    println!("rss start:  {:>8.1} MB", rss_bytes() as f64 / 1_048_576.0);
32
33    let t0 = Instant::now();
34    let mid = iters / 2;
35    for i in 0..iters {
36        let _ = parse_xpath(s);
37        if i == mid {
38            println!("rss mid:    {:>8.1} MB  (after {} parses, {:.2?})",
39                rss_bytes() as f64 / 1_048_576.0, i, t0.elapsed());
40        }
41    }
42    let dt = t0.elapsed();
43    println!("rss end:    {:>8.1} MB  (after {} parses, {:.2?}, {:.0} parses/sec)",
44        rss_bytes() as f64 / 1_048_576.0, iters, dt,
45        iters as f64 / dt.as_secs_f64());
46}