mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 19:21:13 +00:00
Fair reusing of wasm runtime instances (#3011)
* Add test from original bug report Original is from @pepyakin in 3d7b27f3421818e8d6de568e02fbc2947a06246b. I adapted it to work with the latest master. * No longer cleanup module instance * Replace runtime cache with synchronous clone * Fix test * Preserve initial runtime memory and restore it on fetch * Remove leftover comment * Fix style * Improve variable naming * Replace get_into() with get() * Handle missing memory export better * Return earlier when creating runtime first time * Improve comments * fmt * Fix #2967. * Eradicate `code` from `Error::InvalidCode` * tidy * A state snapshot doc. * Store multiple runtimes by hash. * Get rid of deref. * Docs * Use Self for instantiate_module * REVERT ME * Should be ok * Commit * Remove dbg * Use fast-memory's erase * Clean and undo hacks. * Introduce a dedicated error for heap_base * Ban the start function. * Clean, docs and refactor * Add rustflags. * Update Cargo.lock * Apply Basti's suggestions Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Rename allocates_huge_stack_array * Extend TestClientBuilder with set_heap_pages * Update the test. * Update core/executor/src/wasm_executor.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Update core/executor/src/wasm_runtimes_cache.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Update core/executor/src/error.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Update core/executor/src/error.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Fix tests. * Update cargo-lock * Use wasmi master * Use master wasmi * Move tests. * Use wasmi crates.io * Update Cargo.lock * Fix build.rs * Bump runtime version * Revert initial_heap_pages renaming * Bump wasmi up to 0.5.0 * Bump runtime version * Don't restore an instance every now and then * Update core/executor/src/wasm_runtimes_cache.rs Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com> * Propagate error in CacheError * Clarify the get_heap_base call in instantiation * Supply --export=__heap_base See https://reviews.llvm.org/D62744 Co-authored-by: Jim Posen <jim.posen@gmail.com> * Bump version. * Use combinators for segments. * Fix build.rs * Fix build.rs for runtime-test
This commit is contained in:
@@ -256,6 +256,8 @@ cfg_if! {
|
||||
fn use_trie() -> u64;
|
||||
fn benchmark_indirect_call() -> u64;
|
||||
fn benchmark_direct_call() -> u64;
|
||||
fn returns_mutable_static() -> u64;
|
||||
fn allocates_huge_stack_array(trap: bool) -> Vec<u8>;
|
||||
/// Returns the initialized block number.
|
||||
fn get_block_number() -> u64;
|
||||
/// Takes and returns the initialized block number.
|
||||
@@ -287,6 +289,8 @@ cfg_if! {
|
||||
fn use_trie() -> u64;
|
||||
fn benchmark_indirect_call() -> u64;
|
||||
fn benchmark_direct_call() -> u64;
|
||||
fn returns_mutable_static() -> u64;
|
||||
fn allocates_huge_stack_array(trap: bool) -> Vec<u8>;
|
||||
/// Returns the initialized block number.
|
||||
fn get_block_number() -> u64;
|
||||
/// Takes and returns the initialized block number.
|
||||
@@ -404,6 +408,11 @@ fn code_using_trie() -> u64 {
|
||||
iter_pairs.len() as u64
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
/// Mutable static variables should be always observed to have
|
||||
/// the initialized value at the start of a runtime call.
|
||||
static mut MUTABLE_STATIC: u64 = 32;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "std")] {
|
||||
impl_runtime_apis! {
|
||||
@@ -509,6 +518,14 @@ cfg_if! {
|
||||
(0..1000).fold(0, |p, i| p + benchmark_add_one(i))
|
||||
}
|
||||
|
||||
fn returns_mutable_static() -> u64 {
|
||||
unimplemented!("is not expected to be invoked from non-wasm builds");
|
||||
}
|
||||
|
||||
fn allocates_huge_stack_array(_trap: bool) -> Vec<u8> {
|
||||
unimplemented!("is not expected to be invoked from non-wasm builds");
|
||||
}
|
||||
|
||||
fn get_block_number() -> u64 {
|
||||
system::get_block_number().expect("Block number is initialized")
|
||||
}
|
||||
@@ -665,6 +682,41 @@ cfg_if! {
|
||||
(0..10000).fold(0, |p, i| p + benchmark_add_one(i))
|
||||
}
|
||||
|
||||
fn returns_mutable_static() -> u64 {
|
||||
unsafe {
|
||||
MUTABLE_STATIC += 1;
|
||||
MUTABLE_STATIC
|
||||
}
|
||||
}
|
||||
|
||||
fn allocates_huge_stack_array(trap: bool) -> Vec<u8> {
|
||||
// Allocate a stack frame that is approx. 75% of the stack (assuming it is 1MB).
|
||||
// This will just decrease (stacks in wasm32-u-u grow downwards) the stack
|
||||
// pointer. This won't trap on the current compilers.
|
||||
let mut data = [0u8; 1024 * 768];
|
||||
|
||||
// Then make sure we actually write something to it.
|
||||
//
|
||||
// If:
|
||||
// 1. the stack area is placed at the beginning of the linear memory space, and
|
||||
// 2. the stack pointer points to out-of-bounds area, and
|
||||
// 3. a write is performed around the current stack pointer.
|
||||
//
|
||||
// then a trap should happen.
|
||||
//
|
||||
for (i, v) in data.iter_mut().enumerate() {
|
||||
*v = i as u8; // deliberate truncation
|
||||
}
|
||||
|
||||
if trap {
|
||||
// There is a small chance of this to be pulled up in theory. In practice
|
||||
// the probability of that is rather low.
|
||||
panic!()
|
||||
}
|
||||
|
||||
data.to_vec()
|
||||
}
|
||||
|
||||
fn get_block_number() -> u64 {
|
||||
system::get_block_number().expect("Block number is initialized")
|
||||
}
|
||||
@@ -715,3 +767,64 @@ cfg_if! {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
DefaultTestClientBuilderExt, TestClientBuilder,
|
||||
runtime::TestAPI,
|
||||
};
|
||||
use runtime_primitives::{
|
||||
generic::BlockId,
|
||||
traits::ProvideRuntimeApi,
|
||||
};
|
||||
use state_machine::ExecutionStrategy;
|
||||
|
||||
#[test]
|
||||
fn returns_mutable_static() {
|
||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::AlwaysWasm).build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.info().chain.best_number);
|
||||
|
||||
let ret = runtime_api.returns_mutable_static(&block_id).unwrap();
|
||||
assert_eq!(ret, 33);
|
||||
|
||||
// We expect that every invocation will need to return the initial
|
||||
// value plus one. If the value increases more than that then it is
|
||||
// a sign that the wasm runtime preserves the memory content.
|
||||
let ret = runtime_api.returns_mutable_static(&block_id).unwrap();
|
||||
assert_eq!(ret, 33);
|
||||
}
|
||||
|
||||
// If we didn't restore the wasm instance properly, on a trap the stack pointer would not be
|
||||
// returned to its initial value and thus the stack space is going to be leaked.
|
||||
//
|
||||
// See https://github.com/paritytech/substrate/issues/2967 for details
|
||||
#[test]
|
||||
fn restoration_of_globals() {
|
||||
// Allocate 32 pages (of 65536 bytes) which gives the runtime 2048KB of heap to operate on
|
||||
// (plus some additional space unused from the initial pages requested by the wasm runtime
|
||||
// module).
|
||||
//
|
||||
// The fixture performs 2 allocations of 768KB and this theoretically gives 1536KB, however, due
|
||||
// to our allocator algorithm there are inefficiencies.
|
||||
const REQUIRED_MEMORY_PAGES: u64 = 32;
|
||||
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.set_heap_pages(REQUIRED_MEMORY_PAGES)
|
||||
.build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.info().chain.best_number);
|
||||
|
||||
// On the first invocation we allocate approx. 768KB (75%) of stack and then trap.
|
||||
let ret = runtime_api.allocates_huge_stack_array(&block_id, true);
|
||||
assert!(ret.is_err());
|
||||
|
||||
// On the second invocation we allocate yet another 768KB (75%) of stack
|
||||
let ret = runtime_api.allocates_huge_stack_array(&block_id, false);
|
||||
assert!(ret.is_ok());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user