diff --git a/utils/runtime-fuzzer/src/arbitrary_call.rs b/utils/runtime-fuzzer/src/arbitrary_call.rs index e8eb10c5c70..3da212ec059 100644 --- a/utils/runtime-fuzzer/src/arbitrary_call.rs +++ b/utils/runtime-fuzzer/src/arbitrary_call.rs @@ -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::{ @@ -191,11 +192,17 @@ fn config( log_info: Option, ) -> StandardGearWasmConfigsBundle { 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 diff --git a/utils/wasm-gen/src/config/syscalls.rs b/utils/wasm-gen/src/config/syscalls.rs index b9a37a4ed17..c69980e14f9 100644 --- a/utils/wasm-gen/src/config/syscalls.rs +++ b/utils/wasm-gen/src/config/syscalls.rs @@ -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 } @@ -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 } @@ -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(); @@ -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 { + pub fn injection_amounts(&self, name: InvocableSysCall) -> RangeInclusive { self.injection_amounts.get(name) } diff --git a/utils/wasm-gen/src/config/syscalls/amount.rs b/utils/wasm-gen/src/config/syscalls/amount.rs index 10653a8ab74..ba830c8a0b4 100644 --- a/utils/wasm-gen/src/config/syscalls/amount.rs +++ b/utils/wasm-gen/src/config/syscalls/amount.rs @@ -20,36 +20,43 @@ //! //! 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>); +pub struct SysCallsInjectionAmounts(HashMap>); 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) -> 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 { + pub fn get(&self, name: InvocableSysCall) -> RangeInclusive { self.0 .get(&name) .cloned() @@ -57,14 +64,14 @@ impl SysCallsInjectionAmounts { } /// 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)>, + sys_calls_freqs: impl Iterator)>, ) { self.0.extend(sys_calls_freqs) } diff --git a/utils/wasm-gen/src/generator/syscalls.rs b/utils/wasm-gen/src/generator/syscalls.rs index 5b667c216fe..7675c1c38ca 100644 --- a/utils/wasm-gen/src/generator/syscalls.rs +++ b/utils/wasm-gen/src/generator/syscalls.rs @@ -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 { diff --git a/utils/wasm-gen/src/generator/syscalls/imports.rs b/utils/wasm-gen/src/generator/syscalls/imports.rs index 8389f943f08..b066513fabb 100644 --- a/utils/wasm-gen/src/generator/syscalls/imports.rs +++ b/utils/wasm-gen/src/generator/syscalls/imports.rs @@ -223,7 +223,9 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { &mut self, sys_call: SysCallName, ) -> Result> { - 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); diff --git a/utils/wasm-gen/src/tests.rs b/utils/wasm-gen/src/tests.rs index 1f45db0b6fd..121eaa575ff 100644 --- a/utils/wasm-gen/src/tests.rs +++ b/utils/wasm-gen/src/tests.rs @@ -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