Skip to content

Commit

Permalink
feat(wasm-gen): create config for precise sys-calls (#3262)
Browse files Browse the repository at this point in the history
  • Loading branch information
StackOverflowExcept1on authored Sep 18, 2023
1 parent 7fd41cb commit 73d7d82
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 90 deletions.
3 changes: 2 additions & 1 deletion utils/node-loader/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use gear_core::ids::{MessageId, ProgramId};
use gear_core_errors::ReplyCode;
use gear_utils::NonEmpty;
use gear_wasm_gen::{
EntryPointsSet, ParamType, StandardGearWasmConfigsBundle, SysCallName,
EntryPointsSet, InvocableSysCall, ParamType, StandardGearWasmConfigsBundle, SysCallName,
SysCallsInjectionAmounts, SysCallsParamsConfig,
};
use gsdk::metadata::runtime_types::{
Expand Down Expand Up @@ -224,6 +224,7 @@ pub fn get_wasm_gen_config(
(SysCallName::Alloc, 5..=10),
(SysCallName::Free, 5..=10),
]
.map(|(sys_call, range)| (InvocableSysCall::Loose(sys_call), range))
.into_iter(),
);

Expand Down
3 changes: 2 additions & 1 deletion utils/runtime-fuzzer/src/arbitrary_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use arbitrary::{Arbitrary, Result, Unstructured};
use gear_core::ids::{CodeId, ProgramId};
use gear_utils::NonEmpty;
use gear_wasm_gen::{
EntryPointsSet, ParamType, StandardGearWasmConfigsBundle, SysCallName,
EntryPointsSet, InvocableSysCall, ParamType, StandardGearWasmConfigsBundle, SysCallName,
SysCallsInjectionAmounts, SysCallsParamsConfig,
};
use sha1::*;
Expand Down Expand Up @@ -203,6 +203,7 @@ fn config(
(SysCallName::Alloc, 20..=30),
(SysCallName::Free, 20..=30),
]
.map(|(sys_call, range)| (InvocableSysCall::Loose(sys_call), range))
.into_iter(),
);

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*` and `gr_exit` sys-calls must use `gr_source` result for sys-call destination.
pub fn with_source_msg_dest(mut self) -> Self {
self.0.sys_call_destination = SysCallDestination::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
34 changes: 21 additions & 13 deletions utils/wasm-gen/src/config/syscalls/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,59 @@
//!
//! 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 {
Self(
SysCallName::instrumentable()
.into_iter()
.map(|name| (name, (1..=1)))
.collect(),
)
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::new_with_range(0..=0)
}

/// Instantiate a sys-calls amounts ranges map with given range.
fn new_with_range(range: RangeInclusive<u32>) -> Self {
let sys_calls = SysCallName::instrumentable();
Self(
SysCallName::instrumentable()
.into_iter()
.map(|name| (name, (0..=0)))
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(),
)
}

/// 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
38 changes: 38 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,44 @@ impl InvocableSysCall {
}
}

/// Checks whether given sys-call has the precise variant.
pub(crate) fn has_precise_variant(sys_call: SysCallName) -> bool {
Self::required_imports_for_sys_call(sys_call).is_some()
}

/// Returns the required imports to build precise sys-call.
fn required_imports_for_sys_call(sys_call: SysCallName) -> Option<&'static [SysCallName]> {
// NOTE: the last sys-call must be pattern itself
Some(match sys_call {
SysCallName::ReservationSend => {
&[SysCallName::ReserveGas, SysCallName::ReservationSend]
}
SysCallName::ReservationReply => {
&[SysCallName::ReserveGas, SysCallName::ReservationReply]
}
SysCallName::SendCommit => &[
SysCallName::SendInit,
SysCallName::SendPush,
SysCallName::SendCommit,
],
SysCallName::SendCommitWGas => &[
SysCallName::Size,
SysCallName::SendInit,
SysCallName::SendPushInput,
SysCallName::SendCommitWGas,
],
_ => return None,
})
}

/// Returns the required imports to build precise sys-call, but of a fixed size.
fn required_imports<const N: usize>(sys_call: SysCallName) -> &'static [SysCallName; N] {
Self::required_imports_for_sys_call(sys_call)
.expect("failed to find required imports for sys-call")
.try_into()
.expect("failed to convert slice")
}

// 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
Loading

0 comments on commit 73d7d82

Please sign in to comment.