Skip to content

Commit

Permalink
feat(wasm-gen): create config for precise sys-calls
Browse files Browse the repository at this point in the history
  • Loading branch information
StackOverflowExcept1on committed Sep 14, 2023
1 parent 4e263f0 commit 5aba729
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 27 deletions.
19 changes: 13 additions & 6 deletions utils/runtime-fuzzer/src/arbitrary_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ use arbitrary::{Arbitrary, Result, Unstructured};
use gear_core::ids::{CodeId, ProgramId};
use gear_utils::NonEmpty;
use gear_wasm_gen::{
EntryPointsSet, StandardGearWasmConfigsBundle, SysCallName, SysCallsInjectionAmounts,
EntryPointsSet, InvocableSysCall, StandardGearWasmConfigsBundle, SysCallName,
SysCallsInjectionAmounts,
};
use sha1::*;
use std::{
Expand Down Expand Up @@ -191,11 +192,17 @@ fn config(
log_info: Option<String>,
) -> StandardGearWasmConfigsBundle<ProgramId> {
let mut injection_amounts = SysCallsInjectionAmounts::all_once();
injection_amounts.set(SysCallName::Leave, 0, 0);
injection_amounts.set(SysCallName::Panic, 0, 0);
injection_amounts.set(SysCallName::OomPanic, 0, 0);
injection_amounts.set(SysCallName::Send, 20, 30);
injection_amounts.set(SysCallName::Exit, 0, 1);
injection_amounts.set_multiple(
[
(SysCallName::Leave, 0..=0),
(SysCallName::Panic, 0..=0),
(SysCallName::OomPanic, 0..=0),
(SysCallName::Send, 20..=30),
(SysCallName::Exit, 0..=1),
]
.map(|(sys_call, range)| (InvocableSysCall::Loose(sys_call), range))
.into_iter(),
);

let existing_addresses = NonEmpty::collect(
programs
Expand Down
8 changes: 4 additions & 4 deletions utils/wasm-gen/src/config/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl SysCallsConfigBuilder {
/// Set whether `gr_send*` sys-calls must use `gr_source` result for message destination.
pub fn with_source_msg_dest(mut self) -> Self {
self.0.sending_message_destination = MessageDestination::Source;
self.enable_sys_call(SysCallName::Source);
self.enable_sys_call(InvocableSysCall::Loose(SysCallName::Source));

self
}
Expand All @@ -81,7 +81,7 @@ impl SysCallsConfigBuilder {
/// Choosing gear export to log data is done from best `init` to worse `handle`.
pub fn with_log_info(mut self, log: String) -> Self {
self.0.log_info = Some(log);
self.enable_sys_call(SysCallName::Debug);
self.enable_sys_call(InvocableSysCall::Loose(SysCallName::Debug));

self
}
Expand All @@ -93,7 +93,7 @@ impl SysCallsConfigBuilder {
self
}

fn enable_sys_call(&mut self, name: SysCallName) {
fn enable_sys_call(&mut self, name: InvocableSysCall) {
let range = self.0.injection_amounts.get(name);

let range_start = *range.start();
Expand Down Expand Up @@ -145,7 +145,7 @@ pub struct SysCallsConfig {

impl SysCallsConfig {
/// Get possible number of times (range) the sys-call can be injected in the wasm.
pub fn injection_amounts(&self, name: SysCallName) -> RangeInclusive<u32> {
pub fn injection_amounts(&self, name: InvocableSysCall) -> RangeInclusive<u32> {
self.injection_amounts.get(name)
}

Expand Down
37 changes: 22 additions & 15 deletions utils/wasm-gen/src/config/syscalls/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,58 @@
//!
//! Types here are used to create [`crate::SysCallsConfig`].

use crate::InvocableSysCall;

use gear_wasm_instrument::syscalls::SysCallName;
use std::{collections::HashMap, ops::RangeInclusive};

/// Possible injection amount ranges for each sys-call.
#[derive(Debug, Clone)]
pub struct SysCallsInjectionAmounts(HashMap<SysCallName, RangeInclusive<u32>>);
pub struct SysCallsInjectionAmounts(HashMap<InvocableSysCall, RangeInclusive<u32>>);

impl SysCallsInjectionAmounts {
/// Instantiate a sys-calls amounts ranges map, where each gear sys-call is injected into wasm-module only once.
pub fn all_once() -> Self {
fn new_with_range(range: RangeInclusive<u32>) -> Self {
let sys_calls = SysCallName::instrumentable();
Self(
SysCallName::instrumentable()
.into_iter()
.map(|name| (name, (1..=1)))
sys_calls
.iter()
.cloned()
.map(|name| (InvocableSysCall::Loose(name), range.clone()))
.chain(sys_calls.iter().cloned().filter_map(|name| {
InvocableSysCall::has_precise_variant(name)
.then_some((InvocableSysCall::Precise(name), range.clone()))
}))
.collect(),
)
}

/// Instantiate a sys-calls amounts ranges map, where each gear sys-call is injected into wasm-module only once.
pub fn all_once() -> Self {
Self::new_with_range(1..=1)
}

/// Instantiate a sys-calls amounts ranges map, where no gear sys-call is ever injected into wasm-module.
pub fn all_never() -> Self {
Self(
SysCallName::instrumentable()
.into_iter()
.map(|name| (name, (0..=0)))
.collect(),
)
Self::new_with_range(0..=0)
}

/// Get amount possible sys-call amount range.
pub fn get(&self, name: SysCallName) -> RangeInclusive<u32> {
pub fn get(&self, name: InvocableSysCall) -> RangeInclusive<u32> {
self.0
.get(&name)
.cloned()
.expect("instantiated with all sys-calls set")
}

/// Sets possible amount range for the the sys-call.
pub fn set(&mut self, name: SysCallName, min: u32, max: u32) {
pub fn set(&mut self, name: InvocableSysCall, min: u32, max: u32) {
self.0.insert(name, min..=max);
}

/// Same as [`SysCallsAmountRanges::set`], but sets amount ranges for multiple sys-calls.
pub fn set_multiple(
&mut self,
sys_calls_freqs: impl Iterator<Item = (SysCallName, RangeInclusive<u32>)>,
sys_calls_freqs: impl Iterator<Item = (InvocableSysCall, RangeInclusive<u32>)>,
) {
self.0.extend(sys_calls_freqs)
}
Expand Down
10 changes: 10 additions & 0 deletions utils/wasm-gen/src/generator/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ impl InvocableSysCall {
}
}

pub(crate) fn has_precise_variant(sys_call: SysCallName) -> bool {
matches!(
sys_call,
SysCallName::ReservationSend
| SysCallName::ReservationReply
| SysCallName::SendCommit
| SysCallName::SendCommitWGas
)
}

// If syscall changes from fallible into infallible or vice versa in future,
// we'll see it by analyzing code coverage stats produced by fuzzer.
pub(crate) fn is_fallible(&self) -> bool {
Expand Down
4 changes: 3 additions & 1 deletion utils/wasm-gen/src/generator/syscalls/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,9 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> {
&mut self,
sys_call: SysCallName,
) -> Result<Option<(u32, CallIndexesHandle)>> {
let sys_call_amount_range = self.config.injection_amounts(sys_call);
let sys_call_amount_range = self
.config
.injection_amounts(InvocableSysCall::Loose(sys_call));
let sys_call_amount = self.unstructured.int_in_range(sys_call_amount_range)?;
Ok((sys_call_amount != 0).then(|| {
let call_indexes_handle = self.insert_sys_call_import(sys_call);
Expand Down
6 changes: 5 additions & 1 deletion utils/wasm-gen/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,11 @@ fn execute_wasm_with_syscall_injected(
let mut unstructured = Unstructured::new(&buf);

let mut injection_amounts = SysCallsInjectionAmounts::all_never();
injection_amounts.set(syscall, INJECTED_SYSCALLS, INJECTED_SYSCALLS);
injection_amounts.set(
InvocableSysCall::Loose(syscall),
INJECTED_SYSCALLS,
INJECTED_SYSCALLS,
);

let error_processing_config = if ignore_fallible_errors {
ErrorProcessingConfig::None
Expand Down

0 comments on commit 5aba729

Please sign in to comment.