Skip to content

Commit

Permalink
Merge pull request #658 from candy-lang/stricter-lints-in-fuzzer
Browse files Browse the repository at this point in the history
Stricter lints in Fuzzer
  • Loading branch information
jwbot authored Aug 17, 2023
2 parents 066face + 2525998 commit 9224db8
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 21 deletions.
1 change: 1 addition & 0 deletions compiler/fuzzer/src/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ impl<'a> RangeCoverage<'a> {
.count()
}

#[allow(clippy::cast_precision_loss)]
pub fn relative_coverage(&self) -> f64 {
assert!(!self.coverage.is_empty());
let num_covered = self.coverage.count_ones();
Expand Down
20 changes: 14 additions & 6 deletions compiler/fuzzer/src/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub enum Status {
}

impl Fuzzer {
#[must_use]
pub fn new(lir: Rc<Lir>, function: Function, function_id: Id) -> Self {
let mut heap = Heap::default();
let function: Function = Data::from(function.clone_to_heap(&mut heap))
Expand Down Expand Up @@ -70,18 +71,22 @@ impl Fuzzer {
}
}

#[must_use]
pub fn lir(&self) -> Rc<Lir> {
self.lir.clone()
}

#[must_use]
pub fn status(&self) -> &Status {
self.status.as_ref().unwrap()
}
#[must_use]
pub fn into_status(self) -> Status {
self.status.unwrap()
}

pub fn input_pool(&self) -> &InputPool {
#[must_use]
pub const fn input_pool(&self) -> &InputPool {
&self.pool
}

Expand Down Expand Up @@ -132,8 +137,7 @@ impl Fuzzer {
self.function_id
.keys
.last()
.map(|function_name| function_name.to_string())
.unwrap_or_else(|| "{…}".to_string()),
.map_or_else(|| "{…}".to_string(), ToString::to_string),
runner.input,
);
debug!("{}", result.to_string(&call_string));
Expand All @@ -144,12 +148,16 @@ impl Fuzzer {
let function_coverage = total_coverage.in_range(&function_range);

// We favor small inputs with good code coverage.
#[allow(clippy::cast_precision_loss)]
let score = {
let complexity = runner.input.complexity() as Score;
let new_function_coverage = runner.coverage.in_range(&function_range);
let score: Score = (1.5 * runner.num_instructions as f64)
+ (0.1 * new_function_coverage.improvement_on(&function_coverage) as f64)
- 0.4 * complexity;
let coverage_improvement =
new_function_coverage.improvement_on(&function_coverage);

let score = (runner.num_instructions as f64)
.mul_add(1.5, 0.1 * coverage_improvement as f64);
let score: Score = complexity.mul_add(-0.4, score);
score.clamp(0.1, Score::MAX)
};
self.pool.add(runner.input, result, score);
Expand Down
2 changes: 1 addition & 1 deletion compiler/fuzzer/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ impl PartialEq for Input {
}
impl Hash for Input {
fn hash<H: Hasher>(&self, state: &mut H) {
self.arguments.hash(state)
self.arguments.hash(state);
}
}
4 changes: 4 additions & 0 deletions compiler/fuzzer/src/input_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct InputPool {
}

impl InputPool {
#[must_use]
pub fn new(num_args: usize, symbols: Vec<Text>) -> Self {
Self {
heap: Rc::default(),
Expand All @@ -25,6 +26,7 @@ impl InputPool {
}
}

#[must_use]
pub fn generate_new_input(&self) -> Input {
loop {
let input = self.generate_input();
Expand All @@ -33,6 +35,7 @@ impl InputPool {
}
}
}
#[must_use]
pub fn generate_input(&self) -> Input {
let mut rng = ThreadRng::default();

Expand All @@ -53,6 +56,7 @@ impl InputPool {
self.results_and_scores.insert(input, (result, score));
}

#[must_use]
pub fn interesting_inputs(&self) -> Vec<Input> {
self.results_and_scores
.iter()
Expand Down
4 changes: 3 additions & 1 deletion compiler/fuzzer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#![feature(let_chains, round_char_boundary)]
#![warn(clippy::nursery, clippy::pedantic)]
#![allow(clippy::missing_panics_doc, clippy::module_name_repetitions)]

mod coverage;
mod fuzzer;
Expand Down Expand Up @@ -56,7 +58,7 @@ where
for (id, function) in fuzzables {
info!("Fuzzing {id}.");
let mut fuzzer = Fuzzer::new(lir.clone(), function, id.clone());
fuzzer.run(100000);
fuzzer.run(100_000);

match fuzzer.into_status() {
Status::StillFuzzing { total_coverage, .. } => {
Expand Down
16 changes: 9 additions & 7 deletions compiler/fuzzer/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use candy_vm::{StateAfterRunWithoutHandles, VmFinished};
use rustc_hash::FxHashMap;
use std::borrow::Borrow;

const MAX_INSTRUCTIONS: usize = 1000000;
const MAX_INSTRUCTIONS: usize = 1_000_000;

pub struct Runner<L: Borrow<Lir>> {
pub lir: L,
Expand All @@ -22,6 +22,7 @@ pub struct Runner<L: Borrow<Lir>> {
pub result: Option<RunResult>,
}

#[must_use]
pub enum RunResult {
/// Executing the function with the input took more than `MAX_INSTRUCTIONS`.
Timeout,
Expand All @@ -45,14 +46,15 @@ pub enum RunResult {
},
}
impl RunResult {
#[must_use]
pub fn to_string(&self, call: &str) -> String {
match self {
RunResult::Timeout => format!("{call} timed out."),
RunResult::Done { return_value, .. } => format!("{call} returned {return_value}."),
RunResult::NeedsUnfulfilled { reason } => {
Self::Timeout => format!("{call} timed out."),
Self::Done { return_value, .. } => format!("{call} returned {return_value}."),
Self::NeedsUnfulfilled { reason } => {
format!("{call} panicked and it's our fault: {reason}")
}
RunResult::Panicked { panic, .. } => {
Self::Panicked { panic, .. } => {
format!("{call} panicked internally: {}", panic.reason)
}
}
Expand Down Expand Up @@ -83,7 +85,7 @@ impl<L: Borrow<Lir> + Clone> Runner<L> {
StackTracer::default(),
);

Runner {
Self {
lir,
vm: Some(vm),
input,
Expand Down Expand Up @@ -136,7 +138,7 @@ impl<L: Borrow<Lir> + Clone> Runner<L> {
}

if self.num_instructions > MAX_INSTRUCTIONS {
self.result = Some(RunResult::Timeout)
self.result = Some(RunResult::Timeout);
}
}
self.vm = Some(vm);
Expand Down
2 changes: 1 addition & 1 deletion compiler/fuzzer/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ impl Tracer for FuzzablesFinder {
function: Function,
) {
function.dup();
self.fuzzables.insert(definition.get().to_owned(), function);
self.fuzzables.insert(definition.get().clone(), function);
}
}
15 changes: 10 additions & 5 deletions compiler/fuzzer/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub impl InputGeneration for Input {
);
arguments.push(address);
}
Input { heap, arguments }
Self { heap, arguments }
}
fn mutate(&mut self, rng: &mut ThreadRng, symbols: &[Text]) {
let mut heap = self.heap.borrow_mut();
Expand Down Expand Up @@ -164,10 +164,15 @@ impl InlineObjectGeneration for InlineObject {
match self.into() {
Data::Int(int) => match int {
Int::Inline(int) => int.get().bit_length() as usize,
Int::Heap(int) => int.get().bits() as usize,
Int::Heap(int) => int.get().bits().try_into().unwrap_or(usize::MAX),
},
Data::Text(text) => text.byte_len() + 1,
Data::Tag(tag) => 1 + tag.value().map(|it| it.complexity()).unwrap_or_default(),
Data::Tag(tag) => {
1 + tag
.value()
.map(InlineObjectGeneration::complexity)
.unwrap_or_default()
}
Data::List(list) => {
list.items()
.iter()
Expand All @@ -191,7 +196,7 @@ fn mutate_string(rng: &mut ThreadRng, heap: &mut Heap, mut string: String) -> Te
if rng.gen_bool(0.5) && !string.is_empty() {
let start = string.floor_char_boundary(rng.gen_range(0..=string.len()));
let end = string.floor_char_boundary(start + rng.gen_range(0..=(string.len() - start)));
string.replace_range(start..end, "")
string.replace_range(start..end, "");
} else {
let insertion_point = string.floor_char_boundary(rng.gen_range(0..=string.len()));
let string_to_insert = (0..rng.gen_range(0..10))
Expand All @@ -202,7 +207,7 @@ fn mutate_string(rng: &mut ThreadRng, heap: &mut Heap, mut string: String) -> Te
.unwrap()
})
.join("");
string.insert_str(insertion_point, &string_to_insert)
string.insert_str(insertion_point, &string_to_insert);
}
Text::create(heap, true, &string)
}

1 comment on commit 9224db8

@jwbot
Copy link
Collaborator Author

@jwbot jwbot commented on 9224db8 Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compiler

Benchmark suite Current: 9224db8 Previous: 066face Ratio
Time: Compiler/hello_world 16440230 ns/iter (± 435873) 20422297 ns/iter (± 1348749) 0.81
Time: Compiler/fibonacci 147287035 ns/iter (± 1231964) 185746686 ns/iter (± 2959576) 0.79
Time: VM Runtime/hello_world 50600 ns/iter (± 11302) 49402 ns/iter (± 61242) 1.02
Time: VM Runtime/fibonacci/15 253674360 ns/iter (± 750759) 316824020 ns/iter (± 6289979) 0.80
Time: VM Runtime/PLB/binarytrees/6 1174406699 ns/iter (± 7478383) 1450830620 ns/iter (± 12883880) 0.81

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.