Skip to content

Commit a11daf9

Browse files
authored
add cargo fuzz target (#21)
1 parent d184ddd commit a11daf9

File tree

9 files changed

+265
-12
lines changed

9 files changed

+265
-12
lines changed

benches/sherlock.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ pub struct StringModel {
1313
impl StringModel {
1414
#[must_use]
1515
pub fn new(symbols: usize) -> Self {
16-
let fenwick_model = FenwickModel::with_symbols(symbols, 1 << 20);
16+
let fenwick_model = FenwickModel::builder(symbols, 1 << 20)
17+
.panic_on_saturation()
18+
.build();
1719
Self { fenwick_model }
1820
}
1921
}

examples/fenwick_adaptive.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ pub struct StringModel {
1818
impl StringModel {
1919
#[must_use]
2020
pub fn new(alphabet: Vec<char>) -> Self {
21-
let fenwick_model = FenwickModel::with_symbols(alphabet.len(), 1 << 20);
21+
let fenwick_model = FenwickModel::builder(alphabet.len(), 1 << 20)
22+
.panic_on_saturation()
23+
.build();
2224
Self {
2325
alphabet,
2426
fenwick_model,

fenwick-model/src/simple.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,38 @@ use crate::ValueError;
1010
pub struct FenwickModel {
1111
weights: Weights,
1212
max_denominator: u64,
13+
panic_on_saturation: bool,
1314
}
1415

15-
impl FenwickModel {
16-
#[must_use]
17-
pub fn with_symbols(symbols: usize, max_denominator: u64) -> Self {
18-
let weights = Weights::new(symbols);
16+
pub struct Builder {
17+
model: FenwickModel,
18+
}
1919

20-
Self {
20+
impl Builder {
21+
fn new(n_symbols: usize, max_denominator: u64) -> Self {
22+
let weights = Weights::new(n_symbols);
23+
let model = FenwickModel {
2124
weights,
2225
max_denominator,
23-
}
26+
panic_on_saturation: false,
27+
};
28+
Self { model }
29+
}
30+
31+
pub fn panic_on_saturation(mut self) -> Self {
32+
self.model.panic_on_saturation = true;
33+
self
34+
}
35+
36+
pub fn build(self) -> FenwickModel {
37+
self.model
38+
}
39+
}
40+
41+
impl FenwickModel {
42+
#[must_use]
43+
pub fn builder(n_symbols: usize, max_denominator: u64) -> Builder {
44+
Builder::new(n_symbols, max_denominator)
2445
}
2546
}
2647

@@ -57,10 +78,12 @@ impl Model for FenwickModel {
5778
}
5879

5980
fn update(&mut self, symbol: Option<&Self::Symbol>) {
60-
debug_assert!(
61-
self.denominator() < self.max_denominator,
62-
"hit max denominator!"
63-
);
81+
if self.panic_on_saturation {
82+
debug_assert!(
83+
self.denominator() < self.max_denominator,
84+
"hit max denominator!"
85+
);
86+
}
6487
if self.denominator() < self.max_denominator {
6588
self.weights.update(symbol.copied(), 1);
6689
}

fuzz/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
target
2+
corpus
3+
artifacts

fuzz/Cargo.lock

Lines changed: 134 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fuzz/Cargo.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "arithmetic-coding-fuzz"
3+
version = "0.0.0"
4+
authors = ["Automatically generated"]
5+
publish = false
6+
edition = "2018"
7+
8+
[package.metadata]
9+
cargo-fuzz = true
10+
11+
[dependencies]
12+
libfuzzer-sys = "0.4"
13+
arithmetic-coding = { path = ".." }
14+
bitstream-io = "1.2.0"
15+
fenwick-model = { path = "../fenwick-model" }
16+
17+
# Prevent this from interfering with workspaces
18+
[workspace]
19+
members = ["."]
20+
21+
[[bin]]
22+
name = "fuzz_target_1"
23+
path = "fuzz_targets/fuzz_target_1.rs"
24+
test = false
25+
doc = false

fuzz/fuzz_targets/fuzz_target_1.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![no_main]
2+
use fenwick_model::simple::FenwickModel;
3+
use libfuzzer_sys::fuzz_target;
4+
5+
mod round_trip;
6+
7+
fuzz_target!(|data: &[u8]| {
8+
let model = FenwickModel::with_symbols(256, 1 << 20);
9+
let input: Vec<usize> = data.into_iter().copied().map(usize::from).collect();
10+
11+
round_trip::round_trip(model, input);
12+
});

fuzz/fuzz_targets/round_trip.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use arithmetic_coding::{Decoder, Encoder, Model};
2+
use bitstream_io::{BigEndian, BitReader, BitWrite, BitWriter};
3+
4+
pub fn round_trip<M>(model: M, input: Vec<M::Symbol>)
5+
where
6+
M: Model + Clone,
7+
M::Symbol: PartialEq + std::fmt::Debug + Clone,
8+
{
9+
let buffer = encode(model.clone(), input.clone());
10+
let output = decode(model, &buffer);
11+
12+
assert_eq!(input, output);
13+
}
14+
15+
fn encode<M>(model: M, input: Vec<M::Symbol>) -> Vec<u8>
16+
where
17+
M: Model,
18+
{
19+
let mut bitwriter = BitWriter::endian(Vec::new(), BigEndian);
20+
let mut encoder = Encoder::<M>::new(model);
21+
22+
encoder.encode_all(input, &mut bitwriter).expect("failed to encode data!");
23+
bitwriter.byte_align().expect("failed to byte-align the stream");
24+
25+
bitwriter.into_writer()
26+
}
27+
28+
fn decode<M>(model: M, buffer: &[u8]) -> Vec<M::Symbol>
29+
where
30+
M: Model,
31+
{
32+
let bitreader = BitReader::endian(buffer, BigEndian);
33+
let mut decoder = Decoder::new(model, bitreader).expect("failed to initialise decoder");
34+
let mut output = Vec::new();
35+
36+
while let Some(symbol) = decoder.decode_symbol().expect("failed to encode symbol!") {
37+
output.push(symbol);
38+
}
39+
output
40+
}

tests/fuzz.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use fenwick_model::simple::FenwickModel;
2+
3+
mod common;
4+
5+
#[test]
6+
fn round_trip() {
7+
let model = FenwickModel::builder(256, 1 << 20).build();
8+
let bytes: &[u8] = &[220, 255, 255];
9+
let input: Vec<usize> = bytes.iter().copied().map(usize::from).collect();
10+
11+
common::round_trip(model, input);
12+
}

0 commit comments

Comments
 (0)