diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 4124e32263..ecf929384a 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -3234,7 +3234,7 @@ dependencies = [
"sp-std 2.0.0",
"sp-transaction-pool 2.0.0",
"sp-version 2.0.0",
- "substrate-wasm-builder-runner 1.0.4",
+ "substrate-wasm-builder-runner 1.0.5",
]
[[package]]
@@ -3295,7 +3295,7 @@ dependencies = [
"sp-std 2.0.0",
"sp-transaction-pool 2.0.0",
"sp-version 2.0.0",
- "substrate-wasm-builder-runner 1.0.4",
+ "substrate-wasm-builder-runner 1.0.5",
]
[[package]]
@@ -5823,7 +5823,7 @@ dependencies = [
"sp-runtime 2.0.0",
"sp-sandbox 0.8.0",
"sp-std 2.0.0",
- "substrate-wasm-builder-runner 1.0.4",
+ "substrate-wasm-builder-runner 1.0.5",
]
[[package]]
@@ -6693,7 +6693,7 @@ dependencies = [
"sp-io 2.0.0",
"sp-runtime-interface 2.0.0",
"sp-std 2.0.0",
- "substrate-wasm-builder-runner 1.0.4",
+ "substrate-wasm-builder-runner 1.0.5",
]
[[package]]
@@ -7063,7 +7063,7 @@ dependencies = [
"sp-trie 2.0.0",
"sp-version 2.0.0",
"substrate-test-runtime-client 2.0.0",
- "substrate-wasm-builder-runner 1.0.4",
+ "substrate-wasm-builder-runner 1.0.5",
"trie-db 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -7104,7 +7104,7 @@ dependencies = [
[[package]]
name = "substrate-wasm-builder-runner"
-version = "1.0.4"
+version = "1.0.5"
[[package]]
name = "subtle"
diff --git a/substrate/bin/node-template/runtime/build.rs b/substrate/bin/node-template/runtime/build.rs
index 8bdf7584bb..39f7f56feb 100644
--- a/substrate/bin/node-template/runtime/build.rs
+++ b/substrate/bin/node-template/runtime/build.rs
@@ -1,11 +1,10 @@
-use wasm_builder_runner::{build_current_project_with_rustflags, WasmBuilderSource};
+use wasm_builder_runner::WasmBuilder;
fn main() {
- build_current_project_with_rustflags(
- "wasm_binary.rs",
- WasmBuilderSource::Crates("1.0.9"),
- // This instructs LLD to export __heap_base as a global variable, which is used by the
- // external memory allocator.
- "-Clink-arg=--export=__heap_base",
- );
+ WasmBuilder::new()
+ .with_current_project()
+ .with_wasm_builder_from_crates("1.0.9")
+ .export_heap_base()
+ .import_memory()
+ .build()
}
diff --git a/substrate/bin/node/runtime/build.rs b/substrate/bin/node/runtime/build.rs
index 9c81ea6f38..647b476814 100644
--- a/substrate/bin/node/runtime/build.rs
+++ b/substrate/bin/node/runtime/build.rs
@@ -14,17 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
-use wasm_builder_runner::{build_current_project_with_rustflags, WasmBuilderSource};
+use wasm_builder_runner::WasmBuilder;
fn main() {
- build_current_project_with_rustflags(
- "wasm_binary.rs",
- WasmBuilderSource::CratesOrPath {
- path: "../../../utils/wasm-builder",
- version: "1.0.9",
- },
- // This instructs LLD to export __heap_base as a global variable, which is used by the
- // external memory allocator.
- "-Clink-arg=--export=__heap_base",
- );
+ WasmBuilder::new()
+ .with_current_project()
+ .with_wasm_builder_from_crates_or_path("1.0.9", "../../../utils/wasm-builder")
+ .export_heap_base()
+ .import_memory()
+ .build()
}
diff --git a/substrate/client/executor/runtime-test/build.rs b/substrate/client/executor/runtime-test/build.rs
index 9c81ea6f38..647b476814 100644
--- a/substrate/client/executor/runtime-test/build.rs
+++ b/substrate/client/executor/runtime-test/build.rs
@@ -14,17 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
-use wasm_builder_runner::{build_current_project_with_rustflags, WasmBuilderSource};
+use wasm_builder_runner::WasmBuilder;
fn main() {
- build_current_project_with_rustflags(
- "wasm_binary.rs",
- WasmBuilderSource::CratesOrPath {
- path: "../../../utils/wasm-builder",
- version: "1.0.9",
- },
- // This instructs LLD to export __heap_base as a global variable, which is used by the
- // external memory allocator.
- "-Clink-arg=--export=__heap_base",
- );
+ WasmBuilder::new()
+ .with_current_project()
+ .with_wasm_builder_from_crates_or_path("1.0.9", "../../../utils/wasm-builder")
+ .export_heap_base()
+ .import_memory()
+ .build()
}
diff --git a/substrate/client/executor/runtime-test/src/lib.rs b/substrate/client/executor/runtime-test/src/lib.rs
index c0807197b4..f6d37abf94 100644
--- a/substrate/client/executor/runtime-test/src/lib.rs
+++ b/substrate/client/executor/runtime-test/src/lib.rs
@@ -26,6 +26,11 @@ extern "C" {
fn yet_another_missing_external();
}
+#[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;
+
sp_core::wasm_export_functions! {
fn test_calling_missing_external() {
unsafe { missing_external() }
@@ -217,6 +222,41 @@ sp_core::wasm_export_functions! {
fn test_sp_allocator_compiles() {
sp_allocator::FreeingBumpHeapAllocator::new(0);
}
+
+ fn returns_mutable_static() -> u64 {
+ unsafe {
+ MUTABLE_STATIC += 1;
+ MUTABLE_STATIC
+ }
+ }
+
+ fn allocates_huge_stack_array(trap: bool) -> Vec {
+ // 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()
+ }
}
#[cfg(not(feature = "std"))]
diff --git a/substrate/client/executor/src/integration_tests/mod.rs b/substrate/client/executor/src/integration_tests/mod.rs
index 5b2fc5ca0c..ef8171e5ad 100644
--- a/substrate/client/executor/src/integration_tests/mod.rs
+++ b/substrate/client/executor/src/integration_tests/mod.rs
@@ -27,6 +27,7 @@ use sc_runtime_test::WASM_BINARY;
use sp_state_machine::TestExternalities as CoreTestExternalities;
use test_case::test_case;
use sp_trie::{TrieConfiguration, trie_types::Layout};
+use sp_wasm_interface::HostFunctions as _;
use crate::WasmExecutionMethod;
@@ -38,16 +39,14 @@ fn call_in_wasm(
call_data: &[u8],
execution_method: WasmExecutionMethod,
ext: &mut E,
- code: &[u8],
- heap_pages: u64,
) -> crate::error::Result> {
crate::call_in_wasm::(
function,
call_data,
execution_method,
ext,
- code,
- heap_pages,
+ &WASM_BINARY[..],
+ 1024,
true,
)
}
@@ -57,15 +56,12 @@ fn call_in_wasm(
fn returning_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let output = call_in_wasm(
"test_empty_return",
&[],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap();
assert_eq!(output, vec![0u8; 0]);
}
@@ -73,17 +69,14 @@ fn returning_should_work(wasm_method: WasmExecutionMethod) {
#[test_case(WasmExecutionMethod::Interpreted)]
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
fn call_not_existing_function(wasm_method: WasmExecutionMethod) {
- let mut ext = TestExternalities::default();
- let mut ext = ext.ext();
- let test_code = WASM_BINARY;
+ let mut ext = TestExternalities::default();
+ let mut ext = ext.ext();
match call_in_wasm(
"test_calling_missing_external",
&[],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
) {
Ok(_) => panic!("was expected an `Err`"),
Err(e) => {
@@ -107,15 +100,12 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) {
fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
match call_in_wasm(
"test_calling_yet_another_missing_external",
&[],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
) {
Ok(_) => panic!("was expected an `Err`"),
Err(e) => {
@@ -139,15 +129,12 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) {
fn panicking_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let output = call_in_wasm(
"test_panic",
&[],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
);
assert!(output.is_err());
@@ -156,8 +143,6 @@ fn panicking_should_work(wasm_method: WasmExecutionMethod) {
&[0],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
);
assert_eq!(Decode::decode(&mut &output.unwrap()[..]), Ok(Vec::::new()));
@@ -166,8 +151,6 @@ fn panicking_should_work(wasm_method: WasmExecutionMethod) {
&vec![2].encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
);
assert!(output.is_err());
}
@@ -180,15 +163,12 @@ fn storage_should_work(wasm_method: WasmExecutionMethod) {
{
let mut ext = ext.ext();
ext.set_storage(b"foo".to_vec(), b"bar".to_vec());
- let test_code = WASM_BINARY;
let output = call_in_wasm(
"test_data_in",
&b"Hello world".to_vec().encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap();
assert_eq!(output, b"all ok!".to_vec().encode());
@@ -216,7 +196,6 @@ fn clear_prefix_should_work(wasm_method: WasmExecutionMethod) {
ext.set_storage(b"aba".to_vec(), b"3".to_vec());
ext.set_storage(b"abb".to_vec(), b"4".to_vec());
ext.set_storage(b"bbb".to_vec(), b"5".to_vec());
- let test_code = WASM_BINARY;
// This will clear all entries which prefix is "ab".
let output = call_in_wasm(
@@ -224,8 +203,6 @@ fn clear_prefix_should_work(wasm_method: WasmExecutionMethod) {
&b"ab".to_vec().encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap();
assert_eq!(output, b"all ok!".to_vec().encode());
@@ -247,15 +224,12 @@ fn clear_prefix_should_work(wasm_method: WasmExecutionMethod) {
fn blake2_256_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
assert_eq!(
call_in_wasm(
"test_blake2_256",
&[0],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
blake2_256(&b""[..]).to_vec().encode(),
);
@@ -265,8 +239,6 @@ fn blake2_256_should_work(wasm_method: WasmExecutionMethod) {
&b"Hello world!".to_vec().encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
blake2_256(&b"Hello world!"[..]).to_vec().encode(),
);
@@ -277,15 +249,12 @@ fn blake2_256_should_work(wasm_method: WasmExecutionMethod) {
fn blake2_128_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
assert_eq!(
call_in_wasm(
"test_blake2_128",
&[0],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
blake2_128(&b""[..]).to_vec().encode(),
);
@@ -295,8 +264,6 @@ fn blake2_128_should_work(wasm_method: WasmExecutionMethod) {
&b"Hello world!".to_vec().encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
blake2_128(&b"Hello world!"[..]).to_vec().encode(),
);
@@ -307,15 +274,12 @@ fn blake2_128_should_work(wasm_method: WasmExecutionMethod) {
fn sha2_256_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
assert_eq!(
call_in_wasm(
"test_sha2_256",
&[0],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
)
.unwrap(),
hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
@@ -328,8 +292,6 @@ fn sha2_256_should_work(wasm_method: WasmExecutionMethod) {
&b"Hello world!".to_vec().encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
)
.unwrap(),
hex!("c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a")
@@ -343,15 +305,12 @@ fn sha2_256_should_work(wasm_method: WasmExecutionMethod) {
fn twox_256_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
assert_eq!(
call_in_wasm(
"test_twox_256",
&[0],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
hex!(
"99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a"
@@ -363,8 +322,6 @@ fn twox_256_should_work(wasm_method: WasmExecutionMethod) {
&b"Hello world!".to_vec().encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
hex!(
"b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74"
@@ -377,15 +334,12 @@ fn twox_256_should_work(wasm_method: WasmExecutionMethod) {
fn twox_128_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
assert_eq!(
call_in_wasm(
"test_twox_128",
&[0],
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(),
);
@@ -395,8 +349,6 @@ fn twox_128_should_work(wasm_method: WasmExecutionMethod) {
&b"Hello world!".to_vec().encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
hex!("b27dfd7f223f177f2a13647b533599af").to_vec().encode(),
);
@@ -407,7 +359,6 @@ fn twox_128_should_work(wasm_method: WasmExecutionMethod) {
fn ed25519_verify_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let key = ed25519::Pair::from_seed(&blake2_256(b"test"));
let sig = key.sign(b"all ok!");
let mut calldata = vec![];
@@ -420,8 +371,6 @@ fn ed25519_verify_should_work(wasm_method: WasmExecutionMethod) {
&calldata.encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
true.encode(),
);
@@ -437,8 +386,6 @@ fn ed25519_verify_should_work(wasm_method: WasmExecutionMethod) {
&calldata.encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
false.encode(),
);
@@ -449,7 +396,6 @@ fn ed25519_verify_should_work(wasm_method: WasmExecutionMethod) {
fn sr25519_verify_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let key = sr25519::Pair::from_seed(&blake2_256(b"test"));
let sig = key.sign(b"all ok!");
let mut calldata = vec![];
@@ -462,8 +408,6 @@ fn sr25519_verify_should_work(wasm_method: WasmExecutionMethod) {
&calldata.encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
true.encode(),
);
@@ -479,8 +423,6 @@ fn sr25519_verify_should_work(wasm_method: WasmExecutionMethod) {
&calldata.encode(),
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
false.encode(),
);
@@ -490,17 +432,13 @@ fn sr25519_verify_should_work(wasm_method: WasmExecutionMethod) {
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
fn ordered_trie_root_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
- let mut ext = ext.ext();
let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()];
- let test_code = WASM_BINARY;
assert_eq!(
call_in_wasm(
"test_ordered_trie_root",
&[0],
wasm_method,
- &mut ext,
- &test_code[..],
- 8,
+ &mut ext.ext(),
).unwrap(),
Layout::::ordered_trie_root(trie_input.iter()).as_bytes().encode(),
);
@@ -514,16 +452,12 @@ fn offchain_local_storage_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let (offchain, state) = testing::TestOffchainExt::new();
ext.register_extension(OffchainExt::new(offchain));
- let test_code = WASM_BINARY;
- let mut ext = ext.ext();
assert_eq!(
call_in_wasm(
"test_offchain_local_storage",
&[0],
wasm_method,
- &mut ext,
- &test_code[..],
- 8,
+ &mut ext.ext(),
).unwrap(),
true.encode(),
);
@@ -550,17 +484,84 @@ fn offchain_http_should_work(wasm_method: WasmExecutionMethod) {
},
);
- let test_code = WASM_BINARY;
- let mut ext = ext.ext();
assert_eq!(
call_in_wasm(
"test_offchain_http",
&[0],
wasm_method,
- &mut ext,
- &test_code[..],
- 8,
+ &mut ext.ext(),
).unwrap(),
true.encode(),
);
}
+
+#[test_case(WasmExecutionMethod::Interpreted)]
+#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
+#[should_panic(expected = "Allocator ran out of space")]
+fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) {
+ let mut ext = TestExternalities::default();
+
+ crate::call_in_wasm::(
+ "test_exhaust_heap",
+ &[0],
+ wasm_method,
+ &mut ext.ext(),
+ &WASM_BINARY[..],
+ // `17` is the initial number of pages compiled into the binary.
+ 17,
+ true,
+ ).unwrap();
+}
+
+#[test_case(WasmExecutionMethod::Interpreted)]
+#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
+fn returns_mutable_static(wasm_method: WasmExecutionMethod) {
+ let mut instance = crate::wasm_runtime::create_wasm_runtime_with_code(
+ wasm_method,
+ 1024,
+ &WASM_BINARY[..],
+ HostFunctions::host_functions(),
+ true,
+ ).expect("Creates instance");
+
+ let res = instance.call("returns_mutable_static", &[0]).unwrap();
+ assert_eq!(33, u64::decode(&mut &res[..]).unwrap());
+
+ // 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 res = instance.call("returns_mutable_static", &[0]).unwrap();
+ assert_eq!(33, u64::decode(&mut &res[..]).unwrap());
+}
+
+// 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_case(WasmExecutionMethod::Interpreted)]
+#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
+fn restoration_of_globals(wasm_method: WasmExecutionMethod) {
+ // 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 mut instance = crate::wasm_runtime::create_wasm_runtime_with_code(
+ wasm_method,
+ REQUIRED_MEMORY_PAGES,
+ &WASM_BINARY[..],
+ HostFunctions::host_functions(),
+ true,
+ ).expect("Creates instance");
+
+ // On the first invocation we allocate approx. 768KB (75%) of stack and then trap.
+ let res = instance.call("allocates_huge_stack_array", &true.encode());
+ assert!(res.is_err());
+
+ // On the second invocation we allocate yet another 768KB (75%) of stack
+ let res = instance.call("allocates_huge_stack_array", &false.encode());
+ assert!(res.is_ok());
+}
diff --git a/substrate/client/executor/src/integration_tests/sandbox.rs b/substrate/client/executor/src/integration_tests/sandbox.rs
index 9a9b33608d..9458542e3a 100644
--- a/substrate/client/executor/src/integration_tests/sandbox.rs
+++ b/substrate/client/executor/src/integration_tests/sandbox.rs
@@ -18,7 +18,6 @@ use super::{TestExternalities, call_in_wasm};
use crate::WasmExecutionMethod;
use codec::Encode;
-use sc_runtime_test::WASM_BINARY;
use test_case::test_case;
use wabt;
@@ -27,7 +26,6 @@ use wabt;
fn sandbox_should_work(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -56,8 +54,6 @@ fn sandbox_should_work(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
true.encode(),
);
@@ -68,7 +64,6 @@ fn sandbox_should_work(wasm_method: WasmExecutionMethod) {
fn sandbox_trap(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -86,47 +81,16 @@ fn sandbox_trap(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
vec![0],
);
}
-#[test_case(WasmExecutionMethod::Interpreted)]
-#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
-#[should_panic(expected = "Allocator ran out of space")]
-fn sandbox_should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) {
- let mut ext = TestExternalities::default();
- let mut ext = ext.ext();
- let test_code = WASM_BINARY;
-
- let code = wabt::wat2wasm(r#"
- (module
- (import "env" "assert" (func $assert (param i32)))
- (func (export "call")
- i32.const 0
- call $assert
- )
- )
- "#).unwrap().encode();
-
- call_in_wasm(
- "test_exhaust_heap",
- &code,
- wasm_method,
- &mut ext,
- &test_code[..],
- 8,
- ).unwrap();
-}
-
#[test_case(WasmExecutionMethod::Interpreted)]
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
fn start_called(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -161,8 +125,6 @@ fn start_called(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
true.encode(),
);
@@ -173,7 +135,6 @@ fn start_called(wasm_method: WasmExecutionMethod) {
fn invoke_args(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -204,8 +165,6 @@ fn invoke_args(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
true.encode(),
);
@@ -216,7 +175,6 @@ fn invoke_args(wasm_method: WasmExecutionMethod) {
fn return_val(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -235,8 +193,6 @@ fn return_val(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
true.encode(),
);
@@ -247,7 +203,6 @@ fn return_val(wasm_method: WasmExecutionMethod) {
fn unlinkable_module(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -264,8 +219,6 @@ fn unlinkable_module(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
1u8.encode(),
);
@@ -276,7 +229,6 @@ fn unlinkable_module(wasm_method: WasmExecutionMethod) {
fn corrupted_module(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
// Corrupted wasm file
let code = vec![0u8, 0, 0, 0, 1, 0, 0, 0].encode();
@@ -287,8 +239,6 @@ fn corrupted_module(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
1u8.encode(),
);
@@ -299,7 +249,6 @@ fn corrupted_module(wasm_method: WasmExecutionMethod) {
fn start_fn_ok(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -319,8 +268,6 @@ fn start_fn_ok(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
0u8.encode(),
);
@@ -331,7 +278,6 @@ fn start_fn_ok(wasm_method: WasmExecutionMethod) {
fn start_fn_traps(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
let mut ext = ext.ext();
- let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
(module
@@ -352,8 +298,6 @@ fn start_fn_traps(wasm_method: WasmExecutionMethod) {
&code,
wasm_method,
&mut ext,
- &test_code[..],
- 8,
).unwrap(),
2u8.encode(),
);
diff --git a/substrate/client/executor/wasmi/src/lib.rs b/substrate/client/executor/wasmi/src/lib.rs
index cf8125e774..c4701fd827 100644
--- a/substrate/client/executor/wasmi/src/lib.rs
+++ b/substrate/client/executor/wasmi/src/lib.rs
@@ -24,7 +24,7 @@ use wasmi::{
};
use codec::{Encode, Decode};
use sp_core::sandbox as sandbox_primitives;
-use log::{error, trace};
+use log::{error, trace, debug};
use parity_wasm::elements::{deserialize_buffer, DataSegment, Instruction, Module as RawModule};
use sp_wasm_interface::{
FunctionContext, Pointer, WordSize, Sandbox, MemoryId, Result as WResult, Function,
@@ -271,18 +271,36 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
}
}
+/// Will be used on initialization of a module to resolve function and memory imports.
struct Resolver<'a> {
- host_functions: &'a[&'static dyn Function],
+ /// All the hot functions that we export for the WASM blob.
+ host_functions: &'a [&'static dyn Function],
+ /// Should we allow missing function imports?
+ ///
+ /// If `true`, we return a stub that will return an error when being called.
allow_missing_func_imports: bool,
+ /// All the names of functions for that we did not provide a host function.
missing_functions: RefCell>,
+ /// Will be used as initial and maximum size of the imported memory.
+ heap_pages: usize,
+ /// By default, runtimes should import memory and this is `Some(_)` after
+ /// reolving. However, to be backwards compatible, we also support memory
+ /// exported by the WASM blob (this will be `None` after resolving).
+ import_memory: RefCell