From 5aba7291ea9f4fbbba3c7d0042fecbb055b53690 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:17:44 +0300 Subject: [PATCH 01/10] feat(wasm-gen): create config for precise sys-calls --- utils/runtime-fuzzer/src/arbitrary_call.rs | 19 +++++++--- utils/wasm-gen/src/config/syscalls.rs | 8 ++-- utils/wasm-gen/src/config/syscalls/amount.rs | 37 +++++++++++-------- utils/wasm-gen/src/generator/syscalls.rs | 10 +++++ .../src/generator/syscalls/imports.rs | 4 +- utils/wasm-gen/src/tests.rs | 6 ++- 6 files changed, 57 insertions(+), 27 deletions(-) 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 From 999661d0064086efeffc4ba3b2d4a40cbea75f4a Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Thu, 14 Sep 2023 16:39:18 +0300 Subject: [PATCH 02/10] fix gear-node-loader --- utils/node-loader/src/utils.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/node-loader/src/utils.rs b/utils/node-loader/src/utils.rs index 883dba6538a..d63d12ea75a 100644 --- a/utils/node-loader/src/utils.rs +++ b/utils/node-loader/src/utils.rs @@ -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::{ @@ -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(), ); From ad96d1a3800be33fec979beb4a12ebfe89615bc4 Mon Sep 17 00:00:00 2001 From: Sabaun Taraki Date: Thu, 14 Sep 2023 16:53:34 +0300 Subject: [PATCH 03/10] fear(runtime-fuzzer): Introduce `run_corpus` script (#3260) --- utils/runtime-fuzzer/Cargo.toml | 4 ++ utils/runtime-fuzzer/bin/run_corpus.rs | 58 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 utils/runtime-fuzzer/bin/run_corpus.rs diff --git a/utils/runtime-fuzzer/Cargo.toml b/utils/runtime-fuzzer/Cargo.toml index 0c145193e63..410ab54b0f9 100644 --- a/utils/runtime-fuzzer/Cargo.toml +++ b/utils/runtime-fuzzer/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" authors.workspace = true edition.workspace = true +[[bin]] +name = "run_corpus" +path = "bin/run_corpus.rs" + [dependencies] anyhow.workspace = true arbitrary.workspace = true diff --git a/utils/runtime-fuzzer/bin/run_corpus.rs b/utils/runtime-fuzzer/bin/run_corpus.rs new file mode 100644 index 00000000000..fd4e2aaa66b --- /dev/null +++ b/utils/runtime-fuzzer/bin/run_corpus.rs @@ -0,0 +1,58 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Runs provided from the cli corpus +//! +//! Alternatively, `cargo fuzz run` can be used to reproduce some corpus, +//! but it won't give logs of [`GearCalls`] generation, which sheds some +//! light on how `gear-wasm-gen` worked. +//! +//! Also that script can be used to run any bytes input, not only fuzzer's +//! corpus. +//! +//! Just simply run `cargo run --release -- -p `. + +use anyhow::Result; +use arbitrary::{Arbitrary, Unstructured}; +use clap::Parser; +use runtime_fuzzer::{self, GearCalls}; +use std::{fs, path::PathBuf}; + +/// A simple tool to run corpus. +#[derive(Debug, Parser)] +#[command(author, version, about, long_about = None)] +struct Params { + /// Path to the file, which contains corpus. + #[arg(short, long)] + path: PathBuf, +} + +fn main() -> Result<()> { + let params = Params::parse(); + + let corpus_bytes = fs::read(params.path)?; + + gear_utils::init_default_logger(); + + let mut unstructured = Unstructured::new(&corpus_bytes); + let gear_calls = GearCalls::arbitrary(&mut unstructured)?; + + runtime_fuzzer::run(gear_calls); + + Ok(()) +} From 8b8e0a8e079390495b61f5c0a4850e4db2ddb632 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 15 Sep 2023 09:59:15 +0300 Subject: [PATCH 04/10] move `new_with_range()` method under it's users --- utils/wasm-gen/src/config/syscalls/amount.rs | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/utils/wasm-gen/src/config/syscalls/amount.rs b/utils/wasm-gen/src/config/syscalls/amount.rs index ba830c8a0b4..58350dea518 100644 --- a/utils/wasm-gen/src/config/syscalls/amount.rs +++ b/utils/wasm-gen/src/config/syscalls/amount.rs @@ -30,6 +30,17 @@ use std::{collections::HashMap, ops::RangeInclusive}; 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 { + 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) -> Self { let sys_calls = SysCallName::instrumentable(); Self( @@ -45,16 +56,6 @@ 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::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) - } - /// Get amount possible sys-call amount range. pub fn get(&self, name: InvocableSysCall) -> RangeInclusive { self.0 From 6cc9f4553e278317f2b00f12dee7ad2871d7f2a4 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:38:22 +0300 Subject: [PATCH 05/10] rewrite code in better way --- utils/wasm-gen/src/generator/syscalls.rs | 42 ++++++-- .../src/generator/syscalls/imports.rs | 98 ++++++++----------- 2 files changed, 78 insertions(+), 62 deletions(-) diff --git a/utils/wasm-gen/src/generator/syscalls.rs b/utils/wasm-gen/src/generator/syscalls.rs index 7675c1c38ca..20997838ed6 100644 --- a/utils/wasm-gen/src/generator/syscalls.rs +++ b/utils/wasm-gen/src/generator/syscalls.rs @@ -113,14 +113,42 @@ impl InvocableSysCall { } } + /// Checks whether given sys-call has the precise variant. pub(crate) fn has_precise_variant(sys_call: SysCallName) -> bool { - matches!( - sys_call, - SysCallName::ReservationSend - | SysCallName::ReservationReply - | SysCallName::SendCommit - | SysCallName::SendCommitWGas - ) + 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(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, diff --git a/utils/wasm-gen/src/generator/syscalls/imports.rs b/utils/wasm-gen/src/generator/syscalls/imports.rs index b066513fabb..5bd8a46d73c 100644 --- a/utils/wasm-gen/src/generator/syscalls/imports.rs +++ b/utils/wasm-gen/src/generator/syscalls/imports.rs @@ -197,13 +197,26 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { /// Generates precise sys-calls and handles errors if any occurred during generation. fn generate_precise_sys_calls(&mut self) -> Result<()> { - for result in [ - self.generate_send_from_reservation(), - self.generate_reply_from_reservation(), - self.generate_send_commit(), - self.generate_send_commit_with_gas(), - ] { - if let Err(err) = result { + use SysCallName::*; + + #[allow(clippy::type_complexity)] + let sys_calls: [( + SysCallName, + fn(&mut Self, SysCallName) -> Result<(), PreciseSysCallError>, + ); 4] = [ + (ReservationSend, Self::generate_send_from_reservation), + (ReservationReply, Self::generate_reply_from_reservation), + (SendCommit, Self::generate_send_commit), + (SendCommitWGas, Self::generate_send_commit_with_gas), + ]; + + for (sys_call, generate_method) in sys_calls { + log::trace!( + "Constructing {name} sys-call...", + name = InvocableSysCall::Precise(sys_call).to_str() + ); + + if let Err(err) = generate_method(self, sys_call) { match err { PreciseSysCallError::RequiredImports(err) => log::trace!("{err}"), PreciseSysCallError::Arbitrary(err) => return Err(err), @@ -329,13 +342,12 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { log::trace!( "Built proper call to {precise_sys_call_name}", - precise_sys_call_name = InvocableSysCall::Precise(sys_call).to_str() + precise_sys_call_name = invocable_sys_call.to_str() ); let call_indexes_handle = self.call_indexes.len(); self.call_indexes.add_func(func_idx.signature as usize); - // TODO: make separate config for precise sys-calls (#3122) self.sys_calls_imports .insert(invocable_sys_call, (1, call_indexes_handle)); } @@ -357,15 +369,12 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { } /// Generates a function which calls "properly" the `gr_reservation_send`. - fn generate_send_from_reservation(&mut self) -> Result<(), PreciseSysCallError> { - const SYS_CALL: SysCallName = SysCallName::ReservationSend; - log::trace!( - "Constructing {name} sys-call...", - name = InvocableSysCall::Precise(SYS_CALL).to_str() - ); - + fn generate_send_from_reservation( + &mut self, + sys_call: SysCallName, + ) -> Result<(), PreciseSysCallError> { let [reserve_gas_idx, reservation_send_idx] = - self.invocable_sys_calls_indexes(&[SysCallName::ReserveGas, SYS_CALL])?; + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; // subtract to be sure we are in memory boundaries. let rid_pid_value_ptr = self.reserve_memory(); @@ -445,21 +454,18 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { Instruction::End, ]); - self.generate_proper_sys_call_invocation(SYS_CALL, func_instructions); + self.generate_proper_sys_call_invocation(sys_call, func_instructions); Ok(()) } /// Generates a function which calls "properly" the `gr_reservation_reply`. - fn generate_reply_from_reservation(&mut self) -> Result<(), PreciseSysCallError> { - const SYS_CALL: SysCallName = SysCallName::ReservationReply; - log::trace!( - "Constructing {name} sys-call...", - name = InvocableSysCall::Precise(SYS_CALL).to_str() - ); - + fn generate_reply_from_reservation( + &mut self, + sys_call: SysCallName, + ) -> Result<(), PreciseSysCallError> { let [reserve_gas_idx, reservation_reply_idx] = - self.invocable_sys_calls_indexes(&[SysCallName::ReserveGas, SYS_CALL])?; + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; // subtract to be sure we are in memory boundaries. let rid_value_ptr = self.reserve_memory(); @@ -520,25 +526,15 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { Instruction::End, ]); - self.generate_proper_sys_call_invocation(SYS_CALL, func_instructions); + self.generate_proper_sys_call_invocation(sys_call, func_instructions); Ok(()) } /// Generates a function which calls "properly" the `gr_send_commit`. - fn generate_send_commit(&mut self) -> Result<(), PreciseSysCallError> { - const SYS_CALL: SysCallName = SysCallName::SendCommit; - log::trace!( - "Constructing {name} sys-call...", - name = InvocableSysCall::Precise(SYS_CALL).to_str() - ); - + fn generate_send_commit(&mut self, sys_call: SysCallName) -> Result<(), PreciseSysCallError> { let [send_init_idx, send_push_idx, send_commit_idx] = - self.invocable_sys_calls_indexes(&[ - SysCallName::SendInit, - SysCallName::SendPush, - SYS_CALL, - ])?; + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; // subtract to be sure we are in memory boundaries. let handle_ptr = self.reserve_memory(); @@ -622,26 +618,18 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { let func_instructions = Instructions::new(elements); - self.generate_proper_sys_call_invocation(SYS_CALL, func_instructions); + self.generate_proper_sys_call_invocation(sys_call, func_instructions); Ok(()) } /// Generates a function which calls "properly" the `gr_send_commit_wgas`. - fn generate_send_commit_with_gas(&mut self) -> Result<(), PreciseSysCallError> { - const SYS_CALL: SysCallName = SysCallName::SendCommitWGas; - log::trace!( - "Constructing {name} sys-call...", - name = InvocableSysCall::Precise(SYS_CALL).to_str() - ); - - let [size_idx, send_init_idx, send_push_input_idx, send_commit_wgas_idx] = self - .invocable_sys_calls_indexes(&[ - SysCallName::Size, - SysCallName::SendInit, - SysCallName::SendPushInput, - SYS_CALL, - ])?; + fn generate_send_commit_with_gas( + &mut self, + sys_call: SysCallName, + ) -> Result<(), PreciseSysCallError> { + let [size_idx, send_init_idx, send_push_input_idx, send_commit_wgas_idx] = + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; // subtract to be sure we are in memory boundaries. let handle_ptr = self.reserve_memory(); @@ -732,7 +720,7 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { let func_instructions = Instructions::new(elements); - self.generate_proper_sys_call_invocation(SYS_CALL, func_instructions); + self.generate_proper_sys_call_invocation(sys_call, func_instructions); Ok(()) } From 168889a93e40089b5f5d3e1e79fbf6e160cebf59 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 15 Sep 2023 13:31:07 +0300 Subject: [PATCH 06/10] generate precise sys-calls depending on the configuration --- .../src/generator/syscalls/imports.rs | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/utils/wasm-gen/src/generator/syscalls/imports.rs b/utils/wasm-gen/src/generator/syscalls/imports.rs index 5bd8a46d73c..c84aea44d41 100644 --- a/utils/wasm-gen/src/generator/syscalls/imports.rs +++ b/utils/wasm-gen/src/generator/syscalls/imports.rs @@ -57,16 +57,9 @@ pub struct SysCallsImportsGeneratorInstantiator<'a, 'b>( ), ); -/// The set of sys-calls that need to be imported to create precise sys-call. -#[derive(thiserror::Error, Debug)] -#[error("The following sys-calls must be imported: {0:?}")] -pub struct RequiredSysCalls(&'static [SysCallName]); - /// An error that occurs when generating precise sys-call. #[derive(thiserror::Error, Debug)] pub enum PreciseSysCallError { - #[error("{0}")] - RequiredImports(#[from] RequiredSysCalls), #[error("{0}")] Arbitrary(#[from] ArbitraryError), } @@ -211,15 +204,20 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { ]; for (sys_call, generate_method) in sys_calls { - log::trace!( - "Constructing {name} sys-call...", - name = InvocableSysCall::Precise(sys_call).to_str() - ); - - if let Err(err) = generate_method(self, sys_call) { - match err { - PreciseSysCallError::RequiredImports(err) => log::trace!("{err}"), - PreciseSysCallError::Arbitrary(err) => return Err(err), + let sys_call_amount_range = self + .config + .injection_amounts(InvocableSysCall::Precise(sys_call)); + let sys_call_amount = self.unstructured.int_in_range(sys_call_amount_range)?; + for _ in 0..sys_call_amount { + log::trace!( + "Constructing {name} sys-call...", + name = InvocableSysCall::Precise(sys_call).to_str() + ); + + if let Err(err) = generate_method(self, sys_call) { + match err { + PreciseSysCallError::Arbitrary(err) => return Err(err), + } } } } @@ -295,9 +293,9 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { /// Returns the indexes of invocable sys-calls. fn invocable_sys_calls_indexes( - &self, + &mut self, sys_calls: &'static [SysCallName; N], - ) -> Result<[usize; N], RequiredSysCalls> { + ) -> [usize; N] { let mut indexes = [0; N]; for (index, &sys_call) in indexes.iter_mut().zip(sys_calls.iter()) { @@ -305,10 +303,16 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { .sys_calls_imports .get(&InvocableSysCall::Loose(sys_call)) .map(|&(_, call_indexes_handle)| call_indexes_handle) - .ok_or_else(|| RequiredSysCalls(&sys_calls[..]))?; + .unwrap_or_else(|| { + // insert required import when we can't find it + let call_indexes_handle = self.insert_sys_call_import(sys_call); + self.sys_calls_imports + .insert(InvocableSysCall::Loose(sys_call), (0, call_indexes_handle)); + call_indexes_handle + }) } - Ok(indexes) + indexes } /// Generates a function which calls "properly" the given sys-call. @@ -374,7 +378,7 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { sys_call: SysCallName, ) -> Result<(), PreciseSysCallError> { let [reserve_gas_idx, reservation_send_idx] = - self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call)); // subtract to be sure we are in memory boundaries. let rid_pid_value_ptr = self.reserve_memory(); @@ -465,7 +469,7 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { sys_call: SysCallName, ) -> Result<(), PreciseSysCallError> { let [reserve_gas_idx, reservation_reply_idx] = - self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call)); // subtract to be sure we are in memory boundaries. let rid_value_ptr = self.reserve_memory(); @@ -534,7 +538,7 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { /// Generates a function which calls "properly" the `gr_send_commit`. fn generate_send_commit(&mut self, sys_call: SysCallName) -> Result<(), PreciseSysCallError> { let [send_init_idx, send_push_idx, send_commit_idx] = - self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call)); // subtract to be sure we are in memory boundaries. let handle_ptr = self.reserve_memory(); @@ -629,7 +633,7 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { sys_call: SysCallName, ) -> Result<(), PreciseSysCallError> { let [size_idx, send_init_idx, send_push_input_idx, send_commit_wgas_idx] = - self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call))?; + self.invocable_sys_calls_indexes(InvocableSysCall::required_imports(sys_call)); // subtract to be sure we are in memory boundaries. let handle_ptr = self.reserve_memory(); From f4f9965ac12c74e6bf93e1eb1ff13158491fded5 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 15 Sep 2023 13:33:38 +0300 Subject: [PATCH 07/10] trigger CI --- .github/workflows/PR.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index c4379322bff..a5e8e6c6a85 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -2,7 +2,7 @@ name: PR on: pull_request: - branches: [master, vara-stage-1, vara-stage-2, vara-stage-3] + # branches: [master, vara-stage-1, vara-stage-2, vara-stage-3] concurrency: group: ${{ github.workflow }}-${{ github.ref }} From f7147b19f0bc349f79e19dbe4aede4d07a19bf1f Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 15 Sep 2023 19:53:12 +0300 Subject: [PATCH 08/10] simplify `if let` --- utils/wasm-gen/src/generator/syscalls/imports.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/utils/wasm-gen/src/generator/syscalls/imports.rs b/utils/wasm-gen/src/generator/syscalls/imports.rs index c84aea44d41..91887407814 100644 --- a/utils/wasm-gen/src/generator/syscalls/imports.rs +++ b/utils/wasm-gen/src/generator/syscalls/imports.rs @@ -214,10 +214,8 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { name = InvocableSysCall::Precise(sys_call).to_str() ); - if let Err(err) = generate_method(self, sys_call) { - match err { - PreciseSysCallError::Arbitrary(err) => return Err(err), - } + if let Err(PreciseSysCallError::Arbitrary(err)) = generate_method(self, sys_call) { + return Err(err); } } } From 54eae01da933ecacb2f12ba8b0800d14ad2b4e77 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:28:49 +0300 Subject: [PATCH 09/10] Update PR.yml --- .github/workflows/PR.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index a5e8e6c6a85..c4379322bff 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -2,7 +2,7 @@ name: PR on: pull_request: - # branches: [master, vara-stage-1, vara-stage-2, vara-stage-3] + branches: [master, vara-stage-1, vara-stage-2, vara-stage-3] concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 9dece826f4cc877d30fe45aca3ff062c4d86d851 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:30:51 +0300 Subject: [PATCH 10/10] Revert this after force push --- utils/runtime-fuzzer/Cargo.toml | 4 -- utils/runtime-fuzzer/bin/run_corpus.rs | 58 -------------------------- 2 files changed, 62 deletions(-) delete mode 100644 utils/runtime-fuzzer/bin/run_corpus.rs diff --git a/utils/runtime-fuzzer/Cargo.toml b/utils/runtime-fuzzer/Cargo.toml index 410ab54b0f9..0c145193e63 100644 --- a/utils/runtime-fuzzer/Cargo.toml +++ b/utils/runtime-fuzzer/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true -[[bin]] -name = "run_corpus" -path = "bin/run_corpus.rs" - [dependencies] anyhow.workspace = true arbitrary.workspace = true diff --git a/utils/runtime-fuzzer/bin/run_corpus.rs b/utils/runtime-fuzzer/bin/run_corpus.rs deleted file mode 100644 index fd4e2aaa66b..00000000000 --- a/utils/runtime-fuzzer/bin/run_corpus.rs +++ /dev/null @@ -1,58 +0,0 @@ -// This file is part of Gear. - -// Copyright (C) 2021-2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Runs provided from the cli corpus -//! -//! Alternatively, `cargo fuzz run` can be used to reproduce some corpus, -//! but it won't give logs of [`GearCalls`] generation, which sheds some -//! light on how `gear-wasm-gen` worked. -//! -//! Also that script can be used to run any bytes input, not only fuzzer's -//! corpus. -//! -//! Just simply run `cargo run --release -- -p `. - -use anyhow::Result; -use arbitrary::{Arbitrary, Unstructured}; -use clap::Parser; -use runtime_fuzzer::{self, GearCalls}; -use std::{fs, path::PathBuf}; - -/// A simple tool to run corpus. -#[derive(Debug, Parser)] -#[command(author, version, about, long_about = None)] -struct Params { - /// Path to the file, which contains corpus. - #[arg(short, long)] - path: PathBuf, -} - -fn main() -> Result<()> { - let params = Params::parse(); - - let corpus_bytes = fs::read(params.path)?; - - gear_utils::init_default_logger(); - - let mut unstructured = Unstructured::new(&corpus_bytes); - let gear_calls = GearCalls::arbitrary(&mut unstructured)?; - - runtime_fuzzer::run(gear_calls); - - Ok(()) -}