- command_roundtrip: structure-aware (via arbitrary crate) Command encode → parse → equal. Symmetric to cobs_roundtrip. - cobs_decoder_multi_frame: chunked feeding with arbitrary split sizes; asserts bounded payload and that command count never exceeds sentinel count. - cobs_chunk_invariant: same stream through two decoders (chunked vs all-at-once) must produce the same command sequence. Adds test-fuzz-long recipe (600s per target, ~1h 10m total) for CI cron / pre-release. All seven targets smoke-tested at 100k runs each with zero findings.
42 lines
1.1 KiB
Rust
42 lines
1.1 KiB
Rust
//! Chunk-boundary invariance: the same input stream fed into two
|
|
//! decoders — one in arbitrary chunks, one all-at-once — must produce
|
|
//! the same command sequence.
|
|
|
|
#![no_main]
|
|
|
|
use donglora_protocol::Command;
|
|
use donglora_protocol::framing::CobsDecoder;
|
|
use libfuzzer_sys::fuzz_target;
|
|
|
|
fn drain(stream: &[u8], chunk_sched: &[u8]) -> Vec<Command> {
|
|
let mut out: Vec<Command> = Vec::new();
|
|
let mut decoder = CobsDecoder::new();
|
|
let mut cursor = 0;
|
|
let mut idx = 0;
|
|
while cursor < stream.len() {
|
|
let split = if idx < chunk_sched.len() {
|
|
((chunk_sched[idx] as usize) % 64) + 1
|
|
} else {
|
|
16
|
|
};
|
|
idx += 1;
|
|
let end = (cursor + split).min(stream.len());
|
|
decoder.feed(&stream[cursor..end], |c| out.push(c));
|
|
cursor = end;
|
|
}
|
|
out
|
|
}
|
|
|
|
fuzz_target!(|data: &[u8]| {
|
|
let split = 32.min(data.len());
|
|
let (sched, stream) = data.split_at(split);
|
|
|
|
let whole: Vec<Command> = {
|
|
let mut v = Vec::new();
|
|
CobsDecoder::new().feed(stream, |c| v.push(c));
|
|
v
|
|
};
|
|
let chunked = drain(stream, sched);
|
|
assert_eq!(whole, chunked);
|
|
});
|