Skip to content

Commit f6f3f14

Browse files
authored
Merge pull request #79 from fitzgen/custom-mutators
Add support for defining custom mutators
2 parents 56ca914 + e80623e commit f6f3f14

33 files changed

+739
-583
lines changed

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,14 @@ cc = "1.0"
1616

1717
[features]
1818
arbitrary-derive = ["arbitrary/derive"]
19+
20+
[workspace]
21+
members = [
22+
"./example",
23+
"./example_arbitrary",
24+
"./example_mutator",
25+
]
26+
27+
[dev-dependencies]
28+
flate2 = "1.0.20"
29+
rand = "0.8.3"

ci/script.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ cd $(dirname $0)/..
55

66
export CARGO_TARGET_DIR=$(pwd)/target
77

8+
cargo test --doc
9+
810
pushd ./example
911
cargo rustc \
1012
--release \
@@ -39,3 +41,18 @@ RUST_LIBFUZZER_DEBUG_PATH=$(pwd)/debug_output \
3941
cat $(pwd)/debug_output
4042
grep -q Rgb $(pwd)/debug_output
4143
popd
44+
45+
pushd ./example_mutator
46+
cargo rustc \
47+
--release \
48+
-- \
49+
-Cpasses='sancov' \
50+
-Cllvm-args=-sanitizer-coverage-level=3 \
51+
-Cllvm-args=-sanitizer-coverage-trace-compares \
52+
-Cllvm-args=-sanitizer-coverage-inline-8bit-counters \
53+
-Cllvm-args=-sanitizer-coverage-stack-depth \
54+
-Cllvm-args=-sanitizer-coverage-trace-geps \
55+
-Cllvm-args=-sanitizer-coverage-prune-blocks=0 \
56+
-Zsanitizer=address
57+
(! $CARGO_TARGET_DIR/release/example_mutator -runs=10000000)
58+
popd

example/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,5 @@ version = "0.1.0"
44
authors = ["Simonas Kazlauskas <[email protected]>"]
55
edition = "2018"
66

7-
[workspace]
8-
members = ["."]
9-
107
[dependencies]
118
libfuzzer-sys = { path = ".." }

example_arbitrary/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,5 @@ version = "0.1.0"
44
authors = ["Simonas Kazlauskas <[email protected]>"]
55
edition = "2018"
66

7-
[workspace]
8-
members = ["."]
9-
107
[dependencies]
118
libfuzzer-sys = { path = "..", features = ["arbitrary-derive"] }

example_mutator/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
crash-*

example_mutator/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "example_mutator"
3+
version = "0.1.0"
4+
authors = ["Nick Fitzgerald <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
flate2 = "1.0.20"
11+
libfuzzer-sys = { path = ".." }

example_mutator/src/main.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![no_main]
2+
3+
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
4+
use libfuzzer_sys::{fuzz_mutator, fuzz_target};
5+
use std::io::{Read, Write};
6+
7+
fuzz_target!(|data: &[u8]| {
8+
// Decompress the input data and crash if it starts with "boom".
9+
if let Some(data) = decompress(data) {
10+
if data.starts_with(b"boom") {
11+
panic!();
12+
}
13+
}
14+
});
15+
16+
fuzz_mutator!(
17+
|data: &mut [u8], size: usize, max_size: usize, _seed: u32| {
18+
// Decompress the input data. If that fails, use a dummy value.
19+
let mut decompressed = decompress(&data[..size]).unwrap_or_else(|| b"hi".to_vec());
20+
21+
// Mutate the decompressed data with `libFuzzer`'s default mutator. Make
22+
// the `decompressed` vec's extra capacity available for insertion
23+
// mutations via `resize`.
24+
let len = decompressed.len();
25+
let cap = decompressed.capacity();
26+
decompressed.resize(cap, 0);
27+
let new_decompressed_size = libfuzzer_sys::fuzzer_mutate(&mut decompressed, len, cap);
28+
29+
// Recompress the mutated data.
30+
let compressed = compress(&decompressed[..new_decompressed_size]);
31+
32+
// Copy the recompressed mutated data into `data` and return the new size.
33+
let new_size = std::cmp::min(max_size, compressed.len());
34+
data[..new_size].copy_from_slice(&compressed[..new_size]);
35+
new_size
36+
}
37+
);
38+
39+
fn decompress(data: &[u8]) -> Option<Vec<u8>> {
40+
let mut decoder = GzDecoder::new(data);
41+
let mut decompressed = Vec::new();
42+
if decoder.read_to_end(&mut decompressed).is_ok() {
43+
Some(decompressed)
44+
} else {
45+
None
46+
}
47+
}
48+
49+
fn compress(data: &[u8]) -> Vec<u8> {
50+
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
51+
encoder
52+
.write_all(data)
53+
.expect("writing into a vec is infallible");
54+
encoder.finish().expect("writing into a vec is infallible")
55+
}

libfuzzer/CREDITS.TXT

Lines changed: 0 additions & 36 deletions
This file was deleted.

libfuzzer/FuzzerBuiltins.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
2626
inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
2727

2828
inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); }
29-
inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); }
3029
inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); }
3130

3231
} // namespace fuzzer

libfuzzer/FuzzerBuiltinsMsvc.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,6 @@ inline uint32_t Clzll(uint64_t X) {
5252
return 64;
5353
}
5454

55-
inline uint32_t Clz(uint32_t X) {
56-
unsigned long LeadZeroIdx = 0;
57-
if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx;
58-
return 32;
59-
}
60-
6155
inline int Popcountll(unsigned long long X) {
6256
#if !defined(_M_ARM) && !defined(_M_X64)
6357
return __popcnt(X) + __popcnt(X >> 32);

0 commit comments

Comments
 (0)