-
Notifications
You must be signed in to change notification settings - Fork 645
/
runner.rs
107 lines (97 loc) · 3.63 KB
/
runner.rs
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
#![no_main]
use arbitrary::Arbitrary;
use core::fmt;
use near_primitives::contract::ContractCode;
use near_primitives::runtime::fees::RuntimeFeesConfig;
use near_primitives::version::PROTOCOL_VERSION;
use near_vm_logic::mocks::mock_external::MockedExternal;
use near_vm_logic::{VMConfig, VMContext, VMOutcome};
use near_vm_runner::internal::wasmparser::{Export, ExternalKind, Parser, Payload, TypeDef};
use near_vm_runner::internal::VMKind;
use near_vm_runner::VMError;
libfuzzer_sys::fuzz_target!(|module: ArbitraryModule| {
let code = ContractCode::new(module.0.to_bytes(), None);
let (_outcome, _err) = run_fuzz(&code, VMKind::for_protocol_version(PROTOCOL_VERSION));
});
fn run_fuzz(code: &ContractCode, vm_kind: VMKind) -> (Option<VMOutcome>, Option<VMError>) {
let mut fake_external = MockedExternal::new();
let mut context = create_context(vec![]);
context.prepaid_gas = 10u64.pow(14);
let config = VMConfig::test();
let fees = RuntimeFeesConfig::test();
let promise_results = vec![];
let method_name = find_entry_point(code).unwrap_or_else(|| "main".to_string());
vm_kind.runtime(config).unwrap().run(
code,
&method_name,
&mut fake_external,
context,
&fees,
&promise_results,
PROTOCOL_VERSION,
None,
)
}
/// Finds a no-parameter exported function, something like `(func (export "entry-point"))`.
fn find_entry_point(contract: &ContractCode) -> Option<String> {
let mut tys = Vec::new();
let mut fns = Vec::new();
for payload in Parser::default().parse_all(contract.code()) {
match payload {
Ok(Payload::FunctionSection(rdr)) => fns.extend(rdr),
Ok(Payload::TypeSection(rdr)) => tys.extend(rdr),
Ok(Payload::ExportSection(rdr)) => {
for export in rdr {
if let Ok(Export { field, kind: ExternalKind::Function, index }) = export {
if let Some(&Ok(ty_index)) = fns.get(index as usize) {
if let Some(Ok(TypeDef::Func(func_type))) = tys.get(ty_index as usize) {
if func_type.params.is_empty() && func_type.returns.is_empty() {
return Some(field.to_string());
}
}
}
}
}
}
_ => (),
}
}
None
}
fn create_context(input: Vec<u8>) -> VMContext {
VMContext {
current_account_id: "alice".parse().unwrap(),
signer_account_id: "bob".parse().unwrap(),
signer_account_pk: vec![0, 1, 2, 3, 4],
predecessor_account_id: "carol".parse().unwrap(),
input,
block_index: 10,
block_timestamp: 42,
epoch_height: 1,
account_balance: 2u128,
account_locked_balance: 0,
storage_usage: 12,
attached_deposit: 2u128,
prepaid_gas: 10_u64.pow(14),
random_seed: vec![0, 1, 2],
view_config: None,
output_data_receivers: vec![],
}
}
/// Silly wrapper to get more useful Debug.
struct ArbitraryModule(wasm_smith::Module);
impl<'a> Arbitrary<'a> for ArbitraryModule {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
wasm_smith::Module::arbitrary(u).map(ArbitraryModule)
}
}
impl fmt::Debug for ArbitraryModule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes = self.0.to_bytes();
write!(f, "{:?}", bytes)?;
if let Ok(wat) = wasmprinter::print_bytes(&bytes) {
write!(f, "\n{}", wat)?;
}
Ok(())
}
}