diff --git a/utils/wasm-gen/src/generator.rs b/utils/wasm-gen/src/generator.rs index 17089fc2c28..9848ba1b8ee 100644 --- a/utils/wasm-gen/src/generator.rs +++ b/utils/wasm-gen/src/generator.rs @@ -56,6 +56,7 @@ use crate::{utils, GearWasmGeneratorConfig, WasmModule}; use arbitrary::{Result, Unstructured}; use gear_wasm_instrument::parity_wasm::elements::Module; +use std::collections::HashSet; mod entry_points; mod memory; @@ -208,6 +209,20 @@ type CallIndexesHandle = usize; /// and internal functions. struct CallIndexes { inner: Vec, + /// Indexes of wasm-module functions which were newly generated. + /// + /// These are indexes of functions which aren't generated from + /// `wasm-smith` but from the current crate generators. All gear + /// entry points ([`EntryPointsGenerator`]) and custom reservation send + /// function (generated in [`SysCallsImportsGenerator`]) are considered + /// to be "custom" functions. + /// + /// Separating "pre-defined" functions from newly generated ones is important + /// when sys-calls invocator inserts calls of generated sys-calls. For example, + /// calls must not be inserted in the custom function, which perofrms `gr_reservation_send`, + /// not to pollute it's internal instructions structure which is defined such that + /// semantically correct `gr_reservation_send` call is performed. + custom_funcs: HashSet, } impl CallIndexes { @@ -222,19 +237,29 @@ impl CallIndexes { inner.push(FunctionIndex::Func(i as u32)); } - Self { inner } + Self { + inner, + custom_funcs: HashSet::new(), + } } pub(crate) fn get(&self, handle_idx: CallIndexesHandle) -> Option { self.inner.get(handle_idx).copied() } + fn is_custom_func(&self, idx: usize) -> bool { + self.custom_funcs.contains(&idx) + } + fn len(&self) -> usize { self.inner.len() } fn add_func(&mut self, func_idx: usize) { self.inner.push(FunctionIndex::Func(func_idx as u32)); + let is_new = self.custom_funcs.insert(func_idx); + + debug_assert!(is_new, "same inner index is used"); } fn add_import(&mut self, import_idx: usize) { diff --git a/utils/wasm-gen/src/generator/syscalls/invocator.rs b/utils/wasm-gen/src/generator/syscalls/invocator.rs index 583f995af32..23e5d07868c 100644 --- a/utils/wasm-gen/src/generator/syscalls/invocator.rs +++ b/utils/wasm-gen/src/generator/syscalls/invocator.rs @@ -148,7 +148,7 @@ impl<'a> SysCallsInvocator<'a> { fn build_sys_call_invoke_instructions( &mut self, invocable: InvocableSysCall, - call_indexes_handle: usize, + call_indexes_handle: CallIndexesHandle, ) -> Result> { let name = invocable.name(); let signature = invocable.into_signature(); @@ -233,7 +233,7 @@ impl<'a> SysCallsInvocator<'a> { &mut self, params: &[ParamType], results: &[ValueType], - call_indexes_handle: usize, + call_indexes_handle: CallIndexesHandle, ) -> Result> { let results = results.iter().map(|_| Instruction::Drop); @@ -309,6 +309,12 @@ impl<'a> SysCallsInvocator<'a> { let last_funcs_idx = self.module.count_code_funcs() - 1; let insert_into_func_no = self.unstructured.int_in_range(0..=last_funcs_idx)?; + // Do not insert into custom newly generated function, but only into pre-defined + // internal functions. + if self.call_indexes.is_custom_func(insert_into_func_no) { + return Ok(()); + } + self.module.with(|mut module| { let code = module .code_section_mut() @@ -317,12 +323,15 @@ impl<'a> SysCallsInvocator<'a> { .code_mut() .elements_mut(); - let res = self - .unstructured - .int_in_range(0..=code.len() - 1) - .map(|pos| { - code.splice(pos..pos, instructions.iter().cloned()); - }); + // The end of insertion range is second-to-last index, as the last + // index is defined for `Instruction::End` of the function body. + // But if there's only one instruction in the function, then `0` + // index is used as an insertion point. + let last = if code.len() > 1 { code.len() - 2 } else { 0 }; + + let res = self.unstructured.int_in_range(0..=last).map(|pos| { + code.splice(pos..pos, instructions.iter().cloned()); + }); (module, res) })