Skip to content

Commit

Permalink
Save crashes to disk
Browse files Browse the repository at this point in the history
  • Loading branch information
Changochen committed Nov 16, 2023
1 parent 1288358 commit 836949f
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ rayon = "1.5.3"
dashmap = "5.3.4"
#crossbeam = "0.8.1"
psutil = "3.2.2"
bitflags = "2.2.1"
bitflags = {version ="2.2.1", features = ["serde"] }

#[lib]
#proc-macro = true
Expand Down
5 changes: 3 additions & 2 deletions src/datatype.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::mutator::afl_mutator::DeterministicMutationPass;
use serde::{Deserialize, Serialize};
use std::sync::atomic::{AtomicU32, Ordering};

pub type TestCaseID = u32;

#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct TestCaseMetaInfo {
#[allow(dead_code)]
done_pass: DeterministicMutationPass, // All the finished determinsitic passes.
Expand All @@ -28,7 +29,7 @@ impl TestCaseMetaInfo {
}
}

#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct TestCase {
id: TestCaseID, // The id of the test_case itself or the id of parent. Since we won't use both of them at the same time, we reuse the same slot.
mutator_id: u32,
Expand Down
9 changes: 7 additions & 2 deletions src/feedback/bitmap_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ impl FeedbackCollector for BitmapCollector {
let mut crash_counter: HashMap<datatype::MutationInfo, u32> = HashMap::new();
let mut interesting_test_cases = Vec::default();
let mut crash_test_cases = Vec::default();
let mut crashes_vec = Vec::new();

let mut total_timeout: u64 = 0;
let mut total_crash: u64 = 0;
Expand All @@ -100,6 +101,9 @@ impl FeedbackCollector for BitmapCollector {
}
ExecutionStatus::Crash => {
assert!(feedback.contain_test_case());
let test_case_str =
serde_json::to_string(feedback.borrow_test_case().unwrap()).unwrap();
crashes_vec.push(test_case_str);
crash_test_cases.push(feedback);
*crash_counter.entry(mutation_info).or_insert(1) += 1;
total_crash += 1;
Expand All @@ -113,7 +117,8 @@ impl FeedbackCollector for BitmapCollector {

// generate monitor data if any
if total_crash != 0 {
self.monitor_data.push(json!({ "crash": total_crash }));
self.monitor_data
.push(json!({ "crash": total_crash, "testcases": crashes_vec }));
}
if total_timeout != 0 {
self.monitor_data.push(json!({ "timeout": total_timeout }));
Expand Down Expand Up @@ -156,7 +161,7 @@ impl FeedbackCollector for BitmapCollector {

self.interesting_test_cases
.extend(interesting_test_cases.into_iter());
self.crash_test_cases.extend(crash_test_cases.into_iter());
// self.crash_test_cases.extend(crash_test_cases.into_iter());
}

fn get_interesting_test_cases(&mut self, num: Option<usize>) -> Vec<Feedback> {
Expand Down
5 changes: 1 addition & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -965,10 +965,7 @@ pub async fn run_fuzzer_local_async_lock_free_mode(fuzzer: FuzzerConfig) {

let closure = move || {
// TODO: Fix the testcase minimizer
new_queue_frontend::QueueManagerWorker::new_with_seeds(
Some(init_seeds.clone()),
None,
)
new_queue_frontend::QueueManagerWorker::new_with_seeds(Some(init_seeds.clone()), None)
};
let mut queue_manager_frontend =
new_queue_frontend::QueueManagerFrontend::new(Box::new(closure));
Expand Down
43 changes: 43 additions & 0 deletions src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ use std::net::SocketAddr;
use std::net::{IpAddr, Ipv4Addr};
use std::sync::{Arc, Mutex, RwLock};

use crate::datatype::TestCase;
use crate::executor::ExecutionStatus;

use self::output_writer::OutputWriter;

pub mod output_writer;
pub mod rpc;
pub mod stats;
Expand Down Expand Up @@ -48,6 +53,35 @@ pub fn get_worker_num() -> u32 {
WORKER_NUM
}

fn dump_json_testcases(
output_writer: &OutputWriter,
stats: &serde_json::Value,
testcase_type: ExecutionStatus,
) {
let test_case_vec = stats.get("testcases").unwrap().as_array().unwrap();
for test_case_val in test_case_vec {
let test_case_str = test_case_val.as_str().unwrap();
let mut test_case: TestCase = serde_json::from_str(test_case_str).unwrap();
match testcase_type {
ExecutionStatus::Crash => {
test_case.gen_id();
match output_writer.save_crash(&test_case) {
Ok(_v) => {}
Err(_e) => println!("Cannot write crash file"),
}
}
ExecutionStatus::Interesting => {
output_writer.save_queue(&test_case).unwrap();
}
ExecutionStatus::Timeout => {
test_case.gen_id();
output_writer.save_hang(&test_case).unwrap();
}
_ => {}
}
}
}

impl SimpleMonitor {
fn default() -> Self {
SimpleMonitor {
Expand Down Expand Up @@ -112,17 +146,26 @@ impl Monitor for SimpleMonitor {

// TODO: Receive crash/hang/interesting test cases for saving in disk.
fn receive_statistics(&self, stats: serde_json::Value) {
let mut testcase_type = ExecutionStatus::Ok;
if let Some(v) = stats.get("exec") {
self.fuzzer_info.add_exec(v.as_u64().unwrap());
} else if let Some(v) = stats.get("crash") {
self.fuzzer_info.add_crash(v.as_u64().unwrap());
testcase_type = ExecutionStatus::Crash;
} else if let Some(v) = stats.get("timeout") {
self.fuzzer_info.add_timeout_exec(v.as_u64().unwrap());
} else if let Some(v) = stats.get("interesting_test_case") {
self.fuzzer_info.add_coverage(v.as_u64().unwrap());
} else {
unreachable!();
}
if self.fuzzer_info.get_output_writer().is_some() && stats.get("testcases").is_some() {
dump_json_testcases(
self.fuzzer_info.get_output_writer().unwrap(),
&stats,
testcase_type,
)
}
}

fn show_statistics(&self) {
Expand Down
8 changes: 8 additions & 0 deletions src/monitor/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ impl FuzzerInfo {
self.start_time = SystemTime::now();
}

pub fn get_output_writer(&self) -> Option<&OutputWriter> {
if self.output_writer.is_some() {
Some(self.output_writer.as_ref().unwrap())
} else {
None
}
}

fn simple_calculate(&self) {
let elapsed_time = (self.start_time.elapsed().unwrap().as_millis() as u64).max(1);
let last_print_time = self.last_print_time.swap(elapsed_time, Ordering::Relaxed);
Expand Down
3 changes: 2 additions & 1 deletion src/mutator/afl_mutator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rand::seq::SliceRandom;
use rand::Rng;
use rand::SeedableRng;
use rand_distr::WeightedAliasIndex;
use serde::{Deserialize, Serialize};

//use super::MutatorFunc;
use core::mem::size_of;
Expand Down Expand Up @@ -85,7 +86,7 @@ pub struct BitFlipMutator {

bitflags! {
//TODO: Each determinitic pass should have a flag.
#[derive(Default, Clone, Debug, Copy)]
#[derive(Default, Clone, Debug, Copy, Serialize, Deserialize)]
pub struct DeterministicMutationPass: u32 {
const BITFLIP1 = 0b1;
const BITFLIP2 = 0b10;
Expand Down

0 comments on commit 836949f

Please sign in to comment.