crates/veilvoice-meta/tests/wav_fuzz.rs
veilvoice-meta · 299 lines · read the source here · or on GitHub
Randomised robustness testing for the RIFF chunk walker.
clean_wav_bytes exists because lofty cannot remove ID3v2 from a WAV, so VeilVoice walks the chunk list itself. That means it parses a container somebody else produced, with every length field under their control, and the textbook setting for an overrun or a loop that never ends.
The properties asserted, for any input at all:
- It returns. No panic, and no unbounded loop: every iteration must advance
pos, whatever the chunk sizes claim. - A success is a valid WAV. If it hands back bytes, those bytes must parse as RIFF/WAVE with a length field that matches what was written, it is not permitted to emit something the next tool chokes on.
- It never invents audio. Output length is bounded by input length.
Set VEILVOICE_FUZZ_ROUNDS to run it longer than the default.
In plain words
Throws damaged and hostile WAV files at the metadata stripper.
A WAV file is a series of labelled sections, and a section that lies about its own size is the classic way to make a program read past the end of what it was given. Every malformed file here has to be refused rather than trusted.
WHAT THIS FILE CONTAINS
299 lines defining 15 functions (0 public), 1 type and 0 constants. Everything below is read out of the source, so it cannot disagree with the code.
The types it owns.
struct Rngline 30
WHAT CALLS WHAT
The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.
The same graph as Mermaid source
%%{init: {"theme":"base","themeVariables":{"background":"#1a1b26","primaryColor":"#1f2335","primaryTextColor":"#c0caf5","primaryBorderColor":"#7aa2f7","secondaryColor":"#16161e","tertiaryColor":"#16161e","lineColor":"#737aa2","textColor":"#c0caf5","mainBkg":"#1f2335","nodeBorder":"#7aa2f7","clusterBkg":"#16161e","clusterBorder":"#2f3549","fontFamily":"ui-monospace, SFMono-Regular, Consolas, monospace","fontSize":"14px"}}}%%
flowchart TD
n_new["Rng::new<br/>line 33"]
n_next_u32["Rng::next_u32<br/>line 36"]
n_below["Rng::below<br/>line 42"]
n_byte["Rng::byte<br/>line 49"]
n_rounds["rounds<br/>line 54"]
n_seed_wav["seed_wav<br/>line 62"]
n_mutate["mutate<br/>line 94"]
n_check_output["check_output<br/>line 168"]
n_the_chunk_walker_survives_hostile_input["the_chunk_walker_survives_hostile_<br/>input<br/>line 192"]
n_the_realistic_policy_survives_hostile_input["the_realistic_policy_survives_hostile_<br/>input<br/>line 208"]
n_pure_noise_is_rejected_or_handled["pure_noise_is_rejected_or_handled<br/>line 224"]
n_cleaning_is_idempotent["cleaning_is_idempotent<br/>line 238"]
n_every_truncation_of_a_valid_file_is_handled["every_truncation_of_a_valid_file_is_<br/>handled<br/>line 250"]
n_a_riff_size_of_u32_max_does_not_overflow_the_length_arithmetic["a_riff_size_of_u32_max_does_not_<br/>overflow_the_length_arithmetic<br/>line 265"]
n_zero_sized_chunks_do_not_stall_the_walker["zero_sized_chunks_do_not_stall_the_<br/>walker<br/>line 282"]
n_a_riff_size_of_u32_max_does_not_overflow_the_length_arithmetic --> n_check_output
n_a_riff_size_of_u32_max_does_not_overflow_the_length_arithmetic --> n_seed_wav
n_below --> n_next_u32
n_byte --> n_next_u32
n_cleaning_is_idempotent --> n_seed_wav
n_every_truncation_of_a_valid_file_is_handled --> n_check_output
n_every_truncation_of_a_valid_file_is_handled --> n_seed_wav
n_pure_noise_is_rejected_or_handled --> n_check_output
n_pure_noise_is_rejected_or_handled --> n_new
n_pure_noise_is_rejected_or_handled --> n_rounds
n_the_chunk_walker_survives_hostile_input --> n_check_output
n_the_chunk_walker_survives_hostile_input --> n_mutate
n_the_chunk_walker_survives_hostile_input --> n_new
n_the_chunk_walker_survives_hostile_input --> n_rounds
n_the_chunk_walker_survives_hostile_input --> n_seed_wav
n_the_realistic_policy_survives_hostile_input --> n_check_output
n_the_realistic_policy_survives_hostile_input --> n_mutate
n_the_realistic_policy_survives_hostile_input --> n_new
n_the_realistic_policy_survives_hostile_input --> n_rounds
n_the_realistic_policy_survives_hostile_input --> n_seed_wav
n_zero_sized_chunks_do_not_stall_the_walker --> n_check_output
click n_new href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L33" "open the source"
click n_next_u32 href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L36" "open the source"
click n_below href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L42" "open the source"
click n_byte href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L49" "open the source"
click n_rounds href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L54" "open the source"
click n_seed_wav href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L62" "open the source"
click n_mutate href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L94" "open the source"
click n_check_output href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L168" "open the source"
click n_the_chunk_walker_survives_hostile_input href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L192" "open the source"
click n_the_realistic_policy_survives_hostile_input href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L208" "open the source"
click n_pure_noise_is_rejected_or_handled href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L224" "open the source"
click n_cleaning_is_idempotent href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L238" "open the source"
click n_every_truncation_of_a_valid_file_is_handled href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L250" "open the source"
click n_a_riff_size_of_u32_max_does_not_overflow_the_length_arithmetic href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L265" "open the source"
click n_zero_sized_chunks_do_not_stall_the_walker href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-meta/tests/wav_fuzz.rs#L282" "open the source"
classDef helper fill:#1f2335,stroke:#bb9af7,color:#c0caf5
class n_new,n_next_u32,n_below,n_byte,n_rounds,n_seed_wav,n_mutate,n_check_output,n_the_chunk_walker_survives_hostile_input,n_the_realistic_policy_survives_hostile_input,n_pure_noise_is_rejected_or_handled,n_cleaning_is_idempotent,n_every_truncation_of_a_valid_file_is_handled,n_a_riff_size_of_u32_max_does_not_overflow_the_length_arithmetic,n_zero_sized_chunks_do_not_stall_the_walker helper
This site loads no third-party script, so it cannot run Mermaid; the diagram above is the same nodes and edges drawn by the generator instead. GitHub renders the source below directly.
ITEMS
| Item | Line | Documentation |
|---|---|---|
Rng struct | 30 | |
Rng::new fn | 33 | |
Rng::next_u32 fn | 36 | |
Rng::below fn | 42 | |
Rng::byte fn | 49 | |
rounds fn | 54 | |
seed_wav fn | 62 | A minimal but genuinely valid WAV to mutate from. |
mutate fn | 94 | Mutations aimed at the chunk walker specifically: the interesting bytes are the 32-bit sizes, so a fifth of the rounds corrupt one deliberately. |
check_output fn | 168 | |
the_chunk_walker_survives_hostile_input fn | 192 | |
the_realistic_policy_survives_hostile_input fn | 208 | Policy::Realistic appends a chunk of its own, which is the one path that can make the output larger than the input. |
pure_noise_is_rejected_or_handled fn | 224 | |
cleaning_is_idempotent fn | 238 | A cleaned file must clean again to itself. |
every_truncation_of_a_valid_file_is_handled fn | 250 | Every truncation of a valid file, which is what a partial download or an interrupted recording actually looks like. |
a_riff_size_of_u32_max_does_not_overflow_the_length_arithmetic fn | 265 | The RIFF size field is a u32 widened to usize and then had 8 added to it. |
zero_sized_chunks_do_not_stall_the_walker fn | 282 | A chunk that declares a size of zero must still advance the walker. |