Skip to content

Commit 3a8afa9

Browse files
committed
feat: add vm asm fuzzer
1 parent a96840a commit 3a8afa9

File tree

5 files changed

+14077
-0
lines changed

5 files changed

+14077
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ tracing = "0.1"
3939
tracing-subscriber = "0.3"
4040
tracing-test = "0.2"
4141

42+
everscale-asm = { git = "https://github.com/broxus/everscale-asm.git", rev = "bbd284a72676300c89ab074bd39cd91fde21d597" }
4243
everscale-asm-macros = { git = "https://github.com/broxus/everscale-asm.git", rev = "bbd284a72676300c89ab074bd39cd91fde21d597" }
4344

4445
tycho-vm = { path = "./vm" }

fuzz/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ test = false
1414
doc = false
1515
bench = false
1616

17+
[[bin]]
18+
name = "vm_asm"
19+
path = "fuzz_targets/vm_asm.rs"
20+
test = false
21+
doc = false
22+
bench = false
23+
24+
[[bin]]
25+
name = "vm_opcode"
26+
path = "fuzz_targets/vm_opcode_fuzz.rs"
27+
test = false
28+
doc = false
29+
bench = false
30+
1731
[[bin]]
1832
name = "action_phase_real"
1933
path = "fuzz_targets/action_phase_real.rs"
@@ -34,3 +48,5 @@ everscale-types = { workspace = true, features = ["arbitrary", "base64"] }
3448
libfuzzer-sys = { workspace = true }
3549
tycho-executor = { path = "../executor" }
3650
tycho-vm = { path = "../vm", features = ["arbitrary"] }
51+
everscale-asm = { workspace = true }
52+
num-bigint = "0.4.6"

fuzz/fuzz_targets/vm_asm.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![no_main]
2+
3+
use everscale_asm::Code;
4+
use libfuzzer_sys::{fuzz_target, Corpus};
5+
use tycho_vm::{CustomSmcInfo, GasParams, SafeRc, VmState};
6+
7+
fuzz_target!(|code: String| -> Corpus {
8+
if !code.chars().all(|c| c.is_ascii_graphic() || c == ' ') {
9+
return Corpus::Reject;
10+
}
11+
12+
let code = match Code::assemble(&code) {
13+
Ok(code) => code,
14+
Err(_) => return Corpus::Reject,
15+
};
16+
17+
let mut vm = VmState::builder()
18+
.with_code(code)
19+
.with_smc_info(CustomSmcInfo {
20+
version: VmState::DEFAULT_VERSION,
21+
c7: SafeRc::new(Vec::new()),
22+
})
23+
.with_gas(GasParams::getter())
24+
.build();
25+
26+
_ = vm.run();
27+
Corpus::Keep
28+
});

fuzz/fuzz_targets/vm_opcode_fuzz.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#![no_main]
2+
3+
use arbitrary::Arbitrary;
4+
use everscale_types::arbitrary::OrdinaryCell;
5+
use everscale_types::cell::CellBuilder;
6+
use libfuzzer_sys::{fuzz_target, Corpus};
7+
use num_bigint::BigInt;
8+
use tycho_vm::{CustomSmcInfo, GasParams, RcStackValue, SafeRc, Stack, Tuple, VmState};
9+
10+
#[derive(Debug, Arbitrary)]
11+
enum ArbitraryStackValue {
12+
Null,
13+
Int(BigInt),
14+
NaN,
15+
Cell(OrdinaryCell),
16+
EmptyBuilder,
17+
Tuple(Vec<ArbitraryStackValue>),
18+
}
19+
20+
fn arbitrary_to_rc(item: ArbitraryStackValue) -> Option<RcStackValue> {
21+
Some(match item {
22+
ArbitraryStackValue::Null => Stack::make_null(),
23+
ArbitraryStackValue::Int(val) if val.bits() <= 256 => SafeRc::new_dyn_value(val),
24+
ArbitraryStackValue::NaN => Stack::make_nan(),
25+
ArbitraryStackValue::Cell(OrdinaryCell(cell)) => SafeRc::new_dyn_value(cell),
26+
ArbitraryStackValue::EmptyBuilder => SafeRc::new_dyn_value(CellBuilder::new()),
27+
ArbitraryStackValue::Tuple(items) => {
28+
let tuple_items: Tuple = items
29+
.into_iter()
30+
.map(arbitrary_to_rc)
31+
.collect::<Option<Vec<_>>>()?;
32+
SafeRc::new_dyn_value(tuple_items)
33+
}
34+
ArbitraryStackValue::Int(_) => return None,
35+
})
36+
}
37+
38+
#[derive(Debug, Arbitrary)]
39+
struct Input {
40+
code: OrdinaryCell,
41+
initial_stack_items: Vec<ArbitraryStackValue>,
42+
c7_items: Vec<ArbitraryStackValue>,
43+
}
44+
45+
const MAX_ITEMS: usize = 32;
46+
47+
fuzz_target!(|input: Input| -> Corpus {
48+
if input.initial_stack_items.len() > MAX_ITEMS {
49+
return Corpus::Reject;
50+
}
51+
52+
if input.c7_items.len() > MAX_ITEMS {
53+
return Corpus::Reject;
54+
}
55+
56+
let OrdinaryCell(code) = input.code;
57+
58+
let stack_items: Option<Vec<RcStackValue>> = input
59+
.initial_stack_items
60+
.into_iter()
61+
.map(arbitrary_to_rc)
62+
.collect();
63+
64+
let stack_items = match stack_items {
65+
Some(items) => items,
66+
None => return Corpus::Reject,
67+
};
68+
69+
let c7_rc_items: Option<Vec<RcStackValue>> =
70+
input.c7_items.into_iter().map(arbitrary_to_rc).collect();
71+
let c7_rc_items = match c7_rc_items {
72+
Some(items) => items,
73+
None => return Corpus::Reject,
74+
};
75+
76+
let stack = Stack::with_items(stack_items);
77+
78+
let mut vm = VmState::builder()
79+
.with_code(code)
80+
.with_raw_stack(stack.into())
81+
.with_smc_info(CustomSmcInfo {
82+
version: VmState::DEFAULT_VERSION,
83+
c7: SafeRc::new(c7_rc_items),
84+
})
85+
.with_gas(GasParams::getter())
86+
.build();
87+
88+
let _ = vm.run();
89+
90+
Corpus::Keep
91+
});

0 commit comments

Comments
 (0)