1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#![feature(use_extern_macros, decl_macro)]
extern crate lazy_static;
pub use lazy_static::*;
use std::process::{self, Command};
use std::env;
use std::fs;
use std::path::Path;
use std::io;
use std::io::Write;
fn cd_to_crate_root() {
let mut path = env::current_dir().unwrap();
while !path.join("Cargo.toml").is_file() {
path = match path.parent() {
Some(parent) => parent.into(),
None => {
eprintln!("error: could not find `Cargo.toml` in current directory or any parent directory");
process::exit(1);
}
};
}
env::set_current_dir(path).unwrap();
}
pub macro fuzz_marker($marker:expr) {
#[cfg(fuzztest)]
{
use std::env;
use std::fs::File;
lazy_static! {
static ref MARKER_SET: bool = {
let marker: &str = {$marker}.into();
let env_marker = env::var("FUZZTEST_MARKER")
.expect("fuzztest error: environment variable FUZZTEST_MARKER not set");
marker == env_marker
};
}
if *MARKER_SET {
File::create(format!("fuzztest/{}.marker", {$marker}))
.expect("fuzztest error: impossible to create marker file");
panic!("fuzztest: the marker has been successfully hit!");
}
}
}
pub fn check_target_with_marker(target: &str, marker: &str) {
cd_to_crate_root();
let fuzztest_path = Path::new("fuzztest");
if fuzztest_path.is_dir() {
panic!("The fuzztest directory already exists. It might contain important crash data. Please check it out and/or delete it. Aborting... ");
}
fs::create_dir(fuzztest_path).expect("failed to create `fuzztest` directory");
let output = Command::new("cargo")
.args(&["hfuzz", "run", target])
.env("HFUZZ_RUN_ARGS", "-W fuzztest --run_time 5 --exit_upon_crash")
.env("RUSTFLAGS", "--cfg fuzztest")
.env("FUZZTEST_MARKER", marker)
.output()
.expect("failed to launch fuzzer")
;
if !output.status.success() {
fs::remove_dir_all(fuzztest_path).expect("failed to remove `fuzztest` directory");
io::stdout().write(&output.stdout).unwrap();
io::stderr().write(&output.stderr).unwrap();
panic!("fuzztest: fuzzer exited unsuccessfully")
}
let has_crashfile = fs::read_dir(fuzztest_path)
.expect("failed to read `fuzztest` directory")
.map(|f|{f.unwrap().file_name()})
.any(|f|{f.to_string_lossy().ends_with(".fuzz")});
let has_marker_file = fuzztest_path.join(marker).with_extension("marker").is_file();
match (has_marker_file, has_crashfile) {
(true, true) => {
fs::remove_dir_all(fuzztest_path).expect("failed to remove `fuzztest` directory");
},
(true, false) => unreachable!("fuzztest: We got a marker file without a crash file. It's unexpected. Please file a bug report."),
(false, true) => panic!("fuzztest: Ouch, we hit a crash which was not the marker! Please check out the crash file. (`cargo hfuzz run-debug {} fuzztest/*.fuzz`)", target),
(false, false) => {
fs::remove_dir_all(fuzztest_path).expect("failed to remove `fuzztest` directory");
panic!("fuzztest: The fuzzer couldn't find the expected crash marked with `{}`", marker)
},
}
}