Skip to content

Commit

Permalink
Stabilize fuzz program & json (#1344)
Browse files Browse the repository at this point in the history
* Generate program with

* Simplify fuzz_json

* Fuzz config

* Test more args

* Declare STEPS_LIMIT; derive Clone

* Implement location arbitrary by hand

* Implement arbitrary by hand

* Use raw bytes for fuzz_json

* Specify arbitrary for CairoConfig

* Use  and  for json programs

* Add words to dict

* Run carg fix

* Remove unused crates

* Remove unused crates

* Remove comments

* Remove unused crates

* Improve data generation

* Typo

* Allow for Imm errors on final instructions

---------

Co-authored-by: Juanma <[email protected]>
Co-authored-by: Pedro Fontana <[email protected]>
Co-authored-by: Mario Rugiero <[email protected]>
  • Loading branch information
4 people committed Aug 1, 2023
1 parent 47c0411 commit d022cf4
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 659 deletions.
514 changes: 38 additions & 476 deletions fuzzer/Cargo.lock

Large diffs are not rendered by default.

14 changes: 0 additions & 14 deletions fuzzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,8 @@ members = ["."]
arbitrary = { version = "1.3.0", features = ["derive"] }
honggfuzz = "0.5.55"
libfuzzer-sys = "0.4"
bincode = { version = "2.0.0-rc.3", tag = "v2.0.0-rc.3", git = "https://github.com/bincode-org/bincode.git" }
cairo-vm = { path = "../vm", features = ["arbitrary"] }
mimalloc = { version = "0.1.29", default-features = false, optional = true }
nom = "7"
thiserror = { version = "1.0.32" }
cairo-felt = { path = "../felt", features = ["arbitrary"] }
proptest = "1.2.0"

[dev-dependencies]
assert_matches = "1.5.0"
rstest = "0.17.0"


[features]
default = ["with_mimalloc"]
with_mimalloc = ["cairo-vm/with_mimalloc", "mimalloc"]

[[bin]]
name = "fuzz_json"
Expand Down
77 changes: 76 additions & 1 deletion fuzzer/json.dict
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,36 @@
#

"0"
"\"0\""
"\"1\""
"\"2\""
"\"3\""
"\"4\""
"\"5\""
"\"6\""
"\"7\""
"\"8\""
"\"9\""
"\"0"
"\"1"
"\"2"
"\"3"
"\"4"
"\"5"
"\"6"
"\"7"
"\"8"
"\"9"
"0\""
"1\""
"2\""
"3\""
"4\""
"5\""
"6\""
"7\""
"8\""
"9\""
",0"
":0"
"0:"
Expand Down Expand Up @@ -43,6 +73,7 @@
"\\t"
"\\u0000"
"\\x00"
"\\x0"
"\\0"
"\\uD800\\uDC00"
"\\uDBFF\\uDFFF"
Expand All @@ -58,4 +89,48 @@
"@id"

","
":"
":"

# Common cairo words
"\"attributes\""
"\"builtins\""
"\"compiler_version\": \"0.11.0\","
"\"data\""
"\"debug_info\""
"\"file_contents\""
"\"instruction_locations\""
"\"accessible_scopes\""
"\"__main__\""
"\"__main__.main\""
"\"flow_tracking_data\""
"\"ap_tracking\""
"\"group\""
"\"offset\""
"\"reference_ids\""
"\"hints\""
"\"inst\""
"\"end_col\""
"\"end_line\""
"\"start_col\""
"\"start_line\""
"\"input_file\""
"\"filename\""
"\"identifiers\""
"\"decorators\""
"\"pc\""
"\"type\""
"\"value\""
"\"full_name\""
"\"members\""
"\"first_element\""
"\"second_element\""
"\"cairo_type\""
"\"size\""
"Return\""
"SIZEOF_LOCALS\""
"\"main_scope\""
"\"prime\""
"\"reference_manager\""
"\"references\""
"cast"

174 changes: 16 additions & 158 deletions fuzzer/src/fuzz_json.rs
Original file line number Diff line number Diff line change
@@ -1,165 +1,23 @@
use arbitrary::Arbitrary;
use bincode::enc::write::Writer;
use cairo_vm::cairo_run::{self, EncodeTraceError};
use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
use cairo_vm::vm::errors::cairo_run_errors::CairoRunError;
use cairo_vm::vm::errors::trace_errors::TraceError;
use cairo_vm::vm::errors::vm_errors::VirtualMachineError;
use cairo_vm::{
cairo_run::{cairo_run, CairoRunConfig},
hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor,
};
use honggfuzz::fuzz;
use std::fmt;
use std::io::{self, Write};
use std::path::PathBuf;
use thiserror::Error;

#[cfg(feature = "with_mimalloc")]
use mimalloc::MiMalloc;

#[cfg(feature = "with_mimalloc")]
#[global_allocator]
static ALLOC: MiMalloc = MiMalloc;

#[derive(Debug, Arbitrary)]
struct Args {
program_content: Vec<u8>,
trace_file: Option<PathBuf>,
print_output: bool,
entrypoint: String,
memory_file: Option<PathBuf>,
layout: Layout,
proof_mode: bool,
secure_run: Option<bool>,
}

#[derive(Debug, Arbitrary)]
enum Layout {
Plain,
Small,
Dex,
Starknet,
StarknetWithKeccak,
RecursiveLargeOutput,
AllCairo,
AllSolidity,
Dynamic,
}

impl fmt::Display for Layout {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Layout::Plain => write!(f, "plain"),
Layout::Small => write!(f, "small"),
Layout::Dex => write!(f, "dex"),
Layout::Starknet => write!(f, "starknet"),
Layout::StarknetWithKeccak => write!(f, "starknet_with_keccak"),
Layout::RecursiveLargeOutput => write!(f, "recursive_large_output"),
Layout::AllCairo => write!(f, "all_cairo"),
Layout::AllSolidity => write!(f, "all_solidity"),
Layout::Dynamic => write!(f, "dynamic"),
}
}
}

#[derive(Debug, Error)]
enum Error {
#[error("Failed to interact with the file system")]
IO(#[from] std::io::Error),
#[error("The cairo program execution failed")]
Runner(#[from] CairoRunError),
#[error(transparent)]
EncodeTrace(#[from] EncodeTraceError),
#[error(transparent)]
VirtualMachine(#[from] VirtualMachineError),
#[error(transparent)]
Trace(#[from] TraceError),
}

struct FileWriter {
buf_writer: io::BufWriter<std::fs::File>,
bytes_written: usize,
}

impl Writer for FileWriter {
fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> {
self.buf_writer
.write_all(bytes)
.map_err(|e| bincode::error::EncodeError::Io {
inner: e,
index: self.bytes_written,
})?;

self.bytes_written += bytes.len();

Ok(())
}
}

impl FileWriter {
fn new(buf_writer: io::BufWriter<std::fs::File>) -> Self {
Self {
buf_writer,
bytes_written: 0,
}
}

fn flush(&mut self) -> io::Result<()> {
self.buf_writer.flush()
}
}

fn run(args: Args) -> Result<(), Error> {
let trace_enabled = args.trace_file.is_some();
let mut hint_executor = BuiltinHintProcessor::new_empty();
let cairo_run_config = cairo_run::CairoRunConfig {
entrypoint: &args.entrypoint,
trace_enabled,
relocate_mem: args.memory_file.is_some(),
layout: &args.layout.to_string(),
proof_mode: args.proof_mode,
secure_run: args.secure_run,
};

let (cairo_runner, mut vm) =
match cairo_run::cairo_run(&args.program_content, &cairo_run_config, &mut hint_executor) {
Ok(runner) => runner,
Err(error) => {
eprintln!("{error}");
return Err(Error::Runner(error));
}
};

if args.print_output {
let mut output_buffer = "Program Output:\n".to_string();
vm.write_output(&mut output_buffer)?;
print!("{output_buffer}");
}

if let Some(trace_path) = args.trace_file {
let relocated_trace = vm.get_relocated_trace()?;

let trace_file = std::fs::File::create(trace_path)?;
let mut trace_writer =
FileWriter::new(io::BufWriter::with_capacity(3 * 1024 * 1024, trace_file));

cairo_run::write_encoded_trace(relocated_trace, &mut trace_writer)?;
trace_writer.flush()?;
}

if let Some(memory_path) = args.memory_file {
let memory_file = std::fs::File::create(memory_path)?;
let mut memory_writer =
FileWriter::new(io::BufWriter::with_capacity(5 * 1024 * 1024, memory_file));

cairo_run::write_encoded_memory(&cairo_runner.relocated_memory, &mut memory_writer)?;
memory_writer.flush()?;
}

Ok(())
}

fn main() {
loop {
fuzz!(|args: Args| {
let _ = run(args);
fuzz!(|data: (CairoRunConfig, &[u8])| {
let (cairo_run_config, program_json) = data;
let _ = cairo_run(
program_json,
&CairoRunConfig::default(),
&mut BuiltinHintProcessor::new_empty(),
);
let _ = cairo_run(
program_json,
&cairo_run_config,
&mut BuiltinHintProcessor::new_empty(),
);
});
}
}
6 changes: 3 additions & 3 deletions fuzzer/src/fuzz_program.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use cairo_vm::{
cairo_run::{cairo_run_parsed_program, CairoRunConfig},
cairo_run::{cairo_run_fuzzed_program, CairoRunConfig},
hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor,
types::program::Program,
};
Expand All @@ -10,13 +10,13 @@ fn main() {
loop {
fuzz!(|data: (CairoRunConfig, Program)| {
let (cairo_config, program) = data;
let _ = cairo_run_parsed_program(
let _ = cairo_run_fuzzed_program(
program.clone(),
&CairoRunConfig::default(),
&mut BuiltinHintProcessor::new_empty(),
STEPS_LIMIT,
);
let _ = cairo_run_parsed_program(
let _ = cairo_run_fuzzed_program(
program,
&cairo_config,
&mut BuiltinHintProcessor::new_empty(),
Expand Down
21 changes: 19 additions & 2 deletions vm/src/cairo_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,35 @@ use felt::Felt252;
use thiserror_no_std::Error;

#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
use arbitrary::{self, Arbitrary, Unstructured};

#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct CairoRunConfig<'a> {
pub entrypoint: &'a str,
pub trace_enabled: bool,
pub relocate_mem: bool,
#[cfg_attr(feature = "arbitrary", arbitrary(with = arbitrary_layout))]
pub layout: &'a str,
pub proof_mode: bool,
pub secure_run: Option<bool>,
}

#[cfg(feature = "arbitrary")]
fn arbitrary_layout<'a>(u: &mut Unstructured) -> arbitrary::Result<&'a str> {
let layouts = [
"plain",
"small",
"dex",
"starknet",
"starknet_with_keccak",
"recursive_large_output",
"all_cairo",
"all_solidity",
"dynamic",
];
Ok(u.choose(&layouts)?)
}

impl<'a> Default for CairoRunConfig<'a> {
fn default() -> Self {
CairoRunConfig {
Expand Down Expand Up @@ -80,7 +97,7 @@ pub fn cairo_run(
}

#[cfg(feature = "arbitrary")]
pub fn cairo_run_parsed_program(
pub fn cairo_run_fuzzed_program(
program: Program,
cairo_run_config: &CairoRunConfig,
hint_executor: &mut dyn HintProcessor,
Expand Down
Loading

1 comment on commit d022cf4

@github-actions
Copy link

Choose a reason for hiding this comment

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

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.30.

Benchmark suite Current: d022cf4 Previous: 47c0411 Ratio
add_u64_with_felt/1 3 ns/iter (± 0) 2 ns/iter (± 0) 1.50
add_u64_with_felt/2 3 ns/iter (± 0) 2 ns/iter (± 0) 1.50
add_u64_with_felt/3 2 ns/iter (± 0) 1 ns/iter (± 0) 2
add_u64_with_felt/4 2 ns/iter (± 0) 1 ns/iter (± 0) 2
add_u64_with_felt/5 2 ns/iter (± 0) 1 ns/iter (± 0) 2
add_u64_with_felt/6 4 ns/iter (± 0) 2 ns/iter (± 0) 2
add_u64_with_felt/7 4 ns/iter (± 0) 2 ns/iter (± 0) 2
add_u64_with_felt/8 3 ns/iter (± 0) 2 ns/iter (± 0) 1.50

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

CC: @unbalancedparentheses

Please sign in to comment.