added memory/table import limits validation

This commit is contained in:
Svyatoslav Nikolsky
2017-09-04 12:00:01 +03:00
parent 8da7d22e37
commit a85162dcd1
12 changed files with 224 additions and 29 deletions

View File

@ -15,8 +15,7 @@ fn main() {
let program = parity_wasm::DefaultProgramInstance::with_env_params( let program = parity_wasm::DefaultProgramInstance::with_env_params(
interpreter::EnvParams { interpreter::EnvParams {
total_stack: 128*1024, total_stack: 128*1024,
total_memory: 2*1024*1024, ..Default::default()
allow_memory_growth: false,
} }
).expect("Failed to load program"); ).expect("Failed to load program");
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module"); let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");

View File

@ -22,8 +22,7 @@ fn main() {
let program = parity_wasm::DefaultProgramInstance::with_env_params( let program = parity_wasm::DefaultProgramInstance::with_env_params(
interpreter::EnvParams { interpreter::EnvParams {
total_stack: 128*1024, total_stack: 128*1024,
total_memory: 2*1024*1024, ..Default::default()
allow_memory_growth: false,
} }
).expect("Program instance to load"); ).expect("Program instance to load");

View File

@ -1,12 +1,14 @@
use elements; use elements;
use super::invoke::{Invoke, Identity}; use super::invoke::{Invoke, Identity};
#[derive(Debug)]
pub struct MemoryDefinition { pub struct MemoryDefinition {
pub min: u32, pub min: u32,
pub max: Option<u32>, pub max: Option<u32>,
pub data: Vec<MemoryDataDefinition>, pub data: Vec<MemoryDataDefinition>,
} }
#[derive(Debug)]
pub struct MemoryDataDefinition { pub struct MemoryDataDefinition {
pub offset: elements::InitExpr, pub offset: elements::InitExpr,
pub values: Vec<u8>, pub values: Vec<u8>,

View File

@ -217,7 +217,7 @@ impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
/// Push table /// Push table
pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 { pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 {
let entries = self.module.table.entries_mut(); let entries = self.module.table.entries_mut();
entries.push(elements::TableType::new(table.min, Some(table.min))); entries.push(elements::TableType::new(table.min, table.max));
let table_index = (entries.len() - 1) as u32; let table_index = (entries.len() - 1) as u32;
for entry in table.elements.drain(..) { for entry in table.elements.drain(..) {
self.module.element.entries_mut() self.module.element.entries_mut()

View File

@ -1,11 +1,14 @@
use elements; use elements;
use super::invoke::{Invoke, Identity}; use super::invoke::{Invoke, Identity};
#[derive(Debug)]
pub struct TableDefinition { pub struct TableDefinition {
pub min: u32, pub min: u32,
pub max: Option<u32>,
pub elements: Vec<TableEntryDefinition>, pub elements: Vec<TableEntryDefinition>,
} }
#[derive(Debug)]
pub struct TableEntryDefinition { pub struct TableEntryDefinition {
pub offset: elements::InitExpr, pub offset: elements::InitExpr,
pub values: Vec<u32>, pub values: Vec<u32>,
@ -35,6 +38,11 @@ impl<F> TableBuilder<F> where F: Invoke<TableDefinition> {
self self
} }
pub fn with_max(mut self, max: Option<u32>) -> Self {
self.table.max = max;
self
}
pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self { pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self {
self.table.elements.push(TableEntryDefinition { self.table.elements.push(TableEntryDefinition {
offset: elements::InitExpr::new(vec![elements::Opcode::I32Const(index as i32)]), offset: elements::InitExpr::new(vec![elements::Opcode::I32Const(index as i32)]),
@ -52,6 +60,7 @@ impl Default for TableDefinition {
fn default() -> Self { fn default() -> Self {
TableDefinition { TableDefinition {
min: 0, min: 0,
max: None,
elements: Vec::new(), elements: Vec::new(),
} }
} }

View File

@ -96,7 +96,7 @@ impl Serialize for TableType {
} }
/// Memory limits /// Memory limits
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ResizableLimits { pub struct ResizableLimits {
initial: u32, initial: u32,
maximum: Option<u32>, maximum: Option<u32>,

View File

@ -19,7 +19,7 @@ const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
/// Total memory, allocated by default. /// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024; const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
/// Whether memory can be enlarged, or not. /// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = false; const DEFAULT_ALLOW_MEMORY_GROWTH: bool = true;
/// Default tableBase variable value. /// Default tableBase variable value.
const DEFAULT_TABLE_BASE: u32 = 0; const DEFAULT_TABLE_BASE: u32 = 0;
/// Default tableBase variable value. /// Default tableBase variable value.
@ -76,6 +76,8 @@ pub struct EnvParams {
pub total_memory: u32, pub total_memory: u32,
/// Allow memory growth. /// Allow memory growth.
pub allow_memory_growth: bool, pub allow_memory_growth: bool,
/// Table size.
pub table_size: u32,
} }
pub struct EnvModuleInstance<E: UserError> { pub struct EnvModuleInstance<E: UserError> {
@ -180,7 +182,7 @@ pub fn env_module<E: UserError>(params: EnvParams) -> Result<EnvModuleInstance<E
.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY))) .with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
// tables // tables
.table() .table()
.with_min(DEFAULT_TABLE_SIZE) .with_min(params.table_size)
.build() .build()
.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE))) .with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)))
// globals // globals
@ -194,7 +196,7 @@ pub fn env_module<E: UserError>(params: EnvParams) -> Result<EnvModuleInstance<E
.with_export(ExportEntry::new("DYNAMIC_BASE".into(), Internal::Global(INDEX_GLOBAL_DYNAMIC_BASE))) .with_export(ExportEntry::new("DYNAMIC_BASE".into(), Internal::Global(INDEX_GLOBAL_DYNAMIC_BASE)))
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)]))) .with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
.with_export(ExportEntry::new("DYNAMICTOP_PTR".into(), Internal::Global(INDEX_GLOBAL_DYNAMICTOP_PTR))) .with_export(ExportEntry::new("DYNAMICTOP_PTR".into(), Internal::Global(INDEX_GLOBAL_DYNAMICTOP_PTR)))
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, params.allow_memory_growth), InitExpr::new(vec![Opcode::I32Const(params.total_memory as i32)]))) .with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(params.total_memory as i32)])))
.with_export(ExportEntry::new("TOTAL_MEMORY".into(), Internal::Global(INDEX_GLOBAL_TOTAL_MEMORY))) .with_export(ExportEntry::new("TOTAL_MEMORY".into(), Internal::Global(INDEX_GLOBAL_TOTAL_MEMORY)))
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(0)]))) .with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(0)])))
.with_export(ExportEntry::new("ABORT".into(), Internal::Global(INDEX_GLOBAL_ABORT))) .with_export(ExportEntry::new("ABORT".into(), Internal::Global(INDEX_GLOBAL_ABORT)))
@ -235,6 +237,7 @@ impl Default for EnvParams {
total_stack: DEFAULT_TOTAL_STACK, total_stack: DEFAULT_TOTAL_STACK,
total_memory: DEFAULT_TOTAL_MEMORY, total_memory: DEFAULT_TOTAL_MEMORY,
allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH, allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
table_size: DEFAULT_TABLE_SIZE,
} }
} }
} }

View File

@ -1,7 +1,7 @@
use std::u32; use std::u32;
use std::sync::Arc; use std::sync::Arc;
use parking_lot::RwLock; use parking_lot::RwLock;
use elements::MemoryType; use elements::{MemoryType, ResizableLimits};
use interpreter::{Error, UserError}; use interpreter::{Error, UserError};
use interpreter::module::check_limits; use interpreter::module::check_limits;
@ -12,6 +12,8 @@ const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;
/// Linear memory instance. /// Linear memory instance.
pub struct MemoryInstance<E: UserError> { pub struct MemoryInstance<E: UserError> {
/// Memofy limits.
limits: ResizableLimits,
/// Linear memory buffer. /// Linear memory buffer.
buffer: RwLock<Vec<u8>>, buffer: RwLock<Vec<u8>>,
/// Maximum buffer size. /// Maximum buffer size.
@ -51,6 +53,7 @@ impl<E> MemoryInstance<E> where E: UserError {
.ok_or(Error::Memory(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)))?; .ok_or(Error::Memory(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)))?;
let memory = MemoryInstance { let memory = MemoryInstance {
limits: memory_type.limits().clone(),
buffer: RwLock::new(vec![0; initial_size as usize]), buffer: RwLock::new(vec![0; initial_size as usize]),
maximum_size: maximum_size, maximum_size: maximum_size,
_dummy: Default::default(), _dummy: Default::default(),
@ -59,6 +62,11 @@ impl<E> MemoryInstance<E> where E: UserError {
Ok(Arc::new(memory)) Ok(Arc::new(memory))
} }
/// Return linear memory limits.
pub fn limits(&self) -> &ResizableLimits {
&self.limits
}
/// Return linear memory size (in pages). /// Return linear memory size (in pages).
pub fn size(&self) -> u32 { pub fn size(&self) -> u32 {
self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE

View File

@ -304,12 +304,48 @@ impl<E> ModuleInstance<E> where E: UserError {
self.imports.global(externals, import, Some(global_type.content_type().into()))?; self.imports.global(externals, import, Some(global_type.content_type().into()))?;
}, },
&External::Memory(ref memory_type) => { &External::Memory(ref memory_type) => {
check_limits(memory_type.limits())?; let import_limits = memory_type.limits();
self.imports.memory(externals, import)?; check_limits(import_limits)?;
let memory = self.imports.memory(externals, import)?;
let memory_limits = memory.limits();
// a linear-memory import's minimum length is required to be at most the imported linear memory's minimum length.
if import_limits.initial() > memory_limits.initial() {
return Err(Error::Validation(format!("trying to import memory with initial={} and import.initial={}", memory_limits.initial(), import_limits.initial())));
}
// a linear-memory import is required to have a maximum length if the imported linear memory has a maximum length.
// if present, a linear-memory import's maximum length is required to be at least the imported linear memory's maximum length.
match (memory_limits.maximum(), import_limits.maximum()) {
(Some(_), None) | (None, Some(_)) =>
return Err(Error::Validation("trying to import memory with maximum absence mismatch".into())),
(Some(ml), Some(il)) if il < ml =>
return Err(Error::Validation(format!("trying to import memory with maximum={} and import.maximum={}", ml, il))),
_ => (),
}
}, },
&External::Table(ref table_type) => { &External::Table(ref table_type) => {
check_limits(table_type.limits())?; let import_limits = table_type.limits();
self.imports.table(externals, import)?; check_limits(import_limits)?;
let table = self.imports.table(externals, import)?;
let table_limits = table.limits();
// a table import's minimum length is required to be at most the imported table's minimum length.
if import_limits.initial() > table_limits.initial() {
return Err(Error::Validation(format!("trying to import table with initial={} and import.initial={}", table_limits.initial(), import_limits.initial())));
}
// a table import is required to have a maximum length if the imported table has a maximum length.
// if present, a table import's maximum length is required to be at least the imported table's maximum length.
match (table_limits.maximum(), import_limits.maximum()) {
(Some(_), None) | (None, Some(_)) =>
return Err(Error::Validation("trying to import table with maximum absence mismatch".into())),
(Some(ml), Some(il)) if il < ml =>
return Err(Error::Validation(format!("trying to import table with maximum={} and import.maximum={}", ml, il))),
_ => (),
}
}, },
} }
} }
@ -600,7 +636,7 @@ impl<E> ModuleInstanceInterface<E> for ModuleInstance<E> where E: UserError {
})) }))
} }
fn call_internal_function(&self, mut outer: CallerContext<E>, index: u32) -> Result<Option<RuntimeValue>, Error<E>> { fn call_internal_function(&self, outer: CallerContext<E>, index: u32) -> Result<Option<RuntimeValue>, Error<E>> {
let function_type = self.function_type(ItemIndex::Internal(index))?; let function_type = self.function_type(ItemIndex::Internal(index))?;
let args = prepare_function_args(&function_type, outer.value_stack)?; let args = prepare_function_args(&function_type, outer.value_stack)?;
let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index }; let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index };

View File

@ -1,7 +1,7 @@
use std::u32; use std::u32;
use std::sync::Arc; use std::sync::Arc;
use parking_lot::RwLock; use parking_lot::RwLock;
use elements::TableType; use elements::{TableType, ResizableLimits};
use interpreter::{Error, UserError}; use interpreter::{Error, UserError};
use interpreter::module::check_limits; use interpreter::module::check_limits;
use interpreter::variable::{VariableInstance, VariableType}; use interpreter::variable::{VariableInstance, VariableType};
@ -9,6 +9,8 @@ use interpreter::value::RuntimeValue;
/// Table instance. /// Table instance.
pub struct TableInstance<E: UserError> { pub struct TableInstance<E: UserError> {
/// Table limits.
limits: ResizableLimits,
/// Table variables type. /// Table variables type.
variable_type: VariableType, variable_type: VariableType,
/// Table memory buffer. /// Table memory buffer.
@ -27,6 +29,7 @@ impl<E> TableInstance<E> where E: UserError {
let variable_type = table_type.elem_type().into(); let variable_type = table_type.elem_type().into();
Ok(Arc::new(TableInstance { Ok(Arc::new(TableInstance {
limits: table_type.limits().clone(),
variable_type: variable_type, variable_type: variable_type,
buffer: RwLock::new( buffer: RwLock::new(
vec![TableElement::new(VariableInstance::new(true, variable_type, RuntimeValue::Null)?); table_type.limits().initial() as usize] vec![TableElement::new(VariableInstance::new(true, variable_type, RuntimeValue::Null)?); table_type.limits().initial() as usize]
@ -34,6 +37,11 @@ impl<E> TableInstance<E> where E: UserError {
})) }))
} }
/// Return table limits.
pub fn limits(&self) -> &ResizableLimits {
&self.limits
}
/// Get variable type for this table. /// Get variable type for this table.
pub fn variable_type(&self) -> VariableType { pub fn variable_type(&self) -> VariableType {
self.variable_type self.variable_type

View File

@ -5,7 +5,7 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use builder::module; use builder::module;
use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType, use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType,
InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType}; InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType, TableType, MemoryType};
use interpreter::{Error, UserError, ProgramInstance, DefaultProgramInstance, DefaultModuleInstance}; use interpreter::{Error, UserError, ProgramInstance, DefaultProgramInstance, DefaultModuleInstance};
use interpreter::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor}; use interpreter::env_native::{env_native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
@ -456,3 +456,143 @@ fn if_else_with_return_type_validation() {
Opcode::End, Opcode::End,
]).unwrap(); ]).unwrap();
} }
#[test]
fn memory_import_limits_initial() {
let core_module = module()
.memory().with_min(10).build()
.with_export(ExportEntry::new("memory".into(), Internal::Memory(0)))
.build();
let program = DefaultProgramInstance::new().unwrap();
program.add_module("core", core_module, None).unwrap();
let test_cases = vec![
(9, false),
(10, false),
(11, true),
];
for test_case in test_cases {
let (import_initial, is_error) = test_case;
let client_module = module()
.with_import(ImportEntry::new("core".into(), "memory".into(), External::Memory(MemoryType::new(import_initial, None))))
.build();
match program.add_module("client", client_module, None).map(|_| ()) {
Ok(_) if !is_error => (),
Err(Error::Validation(ref actual_error))
if is_error && actual_error == &format!("trying to import memory with initial=10 and import.initial={}", import_initial) => (),
x @ _ => panic!("unexpected result for test_case {:?}: {:?}", test_case, x),
}
}
}
#[test]
fn memory_import_limits_maximum() {
#[derive(Debug, Clone, Copy, PartialEq)]
enum MaximumError { AbsenceMismatch, ValueMismatch, Ok };
let test_cases = vec![
(None, Some(100), MaximumError::AbsenceMismatch),
(Some(100), None, MaximumError::AbsenceMismatch),
(Some(100), Some(98), MaximumError::ValueMismatch),
(Some(100), Some(100), MaximumError::Ok),
(Some(100), Some(101), MaximumError::Ok),
(None, None, MaximumError::Ok),
];
let program = DefaultProgramInstance::new().unwrap();
for test_case in test_cases {
let (core_maximum, client_maximum, expected_err) = test_case;
let core_module = module()
.memory().with_min(10).with_max(core_maximum).build()
.with_export(ExportEntry::new("memory".into(), Internal::Memory(0)))
.build();
let client_module = module()
.with_import(ImportEntry::new("core".into(), "memory".into(), External::Memory(MemoryType::new(10, client_maximum))))
.build();
program.add_module("core", core_module, None).unwrap();
match program.add_module("client", client_module, None).map(|_| ()) {
Err(Error::Validation(actual_err)) => match expected_err {
MaximumError::AbsenceMismatch
if actual_err == "trying to import memory with maximum absence mismatch".to_owned() => (),
MaximumError::ValueMismatch
if actual_err == format!("trying to import memory with maximum={} and import.maximum={}", core_maximum.unwrap_or_default(), client_maximum.unwrap_or_default()) => (),
_ => panic!("unexpected validation error for test_case {:?}: {}", test_case, actual_err),
},
Ok(_) if expected_err == MaximumError::Ok => (),
x @ _ => panic!("unexpected result for test_case {:?}: {:?}", test_case, x),
}
}
}
#[test]
fn table_import_limits_initial() {
let core_module = module()
.table().with_min(10).build()
.with_export(ExportEntry::new("table".into(), Internal::Table(0)))
.build();
let program = DefaultProgramInstance::new().unwrap();
program.add_module("core", core_module, None).unwrap();
let test_cases = vec![
(9, false),
(10, false),
(11, true),
];
for test_case in test_cases {
let (import_initial, is_error) = test_case;
let client_module = module()
.with_import(ImportEntry::new("core".into(), "table".into(), External::Table(TableType::new(import_initial, None))))
.build();
match program.add_module("client", client_module, None).map(|_| ()) {
Ok(_) if !is_error => (),
Err(Error::Validation(ref actual_error))
if is_error && actual_error == &format!("trying to import table with initial=10 and import.initial={}", import_initial) => (),
x @ _ => panic!("unexpected result for test_case {:?}: {:?}", test_case, x),
}
}
}
#[test]
fn table_import_limits_maximum() {
#[derive(Debug, Clone, Copy, PartialEq)]
enum MaximumError { AbsenceMismatch, ValueMismatch, Ok };
let test_cases = vec![
(None, Some(100), MaximumError::AbsenceMismatch),
(Some(100), None, MaximumError::AbsenceMismatch),
(Some(100), Some(98), MaximumError::ValueMismatch),
(Some(100), Some(100), MaximumError::Ok),
(Some(100), Some(101), MaximumError::Ok),
(None, None, MaximumError::Ok),
];
let program = DefaultProgramInstance::new().unwrap();
for test_case in test_cases {
let (core_maximum, client_maximum, expected_err) = test_case;
let core_module = module()
.table().with_min(10).with_max(core_maximum).build()
.with_export(ExportEntry::new("table".into(), Internal::Table(0)))
.build();
let client_module = module()
.with_import(ImportEntry::new("core".into(), "table".into(), External::Table(TableType::new(10, client_maximum))))
.build();
program.add_module("core", core_module, None).unwrap();
match program.add_module("client", client_module, None).map(|_| ()) {
Err(Error::Validation(actual_err)) => match expected_err {
MaximumError::AbsenceMismatch
if actual_err == "trying to import table with maximum absence mismatch".to_owned() => (),
MaximumError::ValueMismatch
if actual_err == format!("trying to import table with maximum={} and import.maximum={}", core_maximum.unwrap_or_default(), client_maximum.unwrap_or_default()) => (),
_ => panic!("unexpected validation error for test_case {:?}: {}", test_case, actual_err),
},
Ok(_) if expected_err == MaximumError::Ok => (),
x @ _ => panic!("unexpected result for test_case {:?}: {:?}", test_case, x),
}
}
}

View File

@ -1,6 +1,6 @@
use elements::deserialize_file; use elements::deserialize_file;
use elements::Module; use elements::Module;
use interpreter::{EnvParams, ExecutionParams, DefaultProgramInstance}; use interpreter::{ExecutionParams, DefaultProgramInstance};
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
use interpreter::module::{ModuleInstanceInterface, ItemIndex}; use interpreter::module::{ModuleInstanceInterface, ItemIndex};
@ -11,12 +11,7 @@ fn interpreter_inc_i32() {
// The WASM file containing the module and function // The WASM file containing the module and function
const WASM_FILE: &str = &"res/cases/v1/inc_i32.wasm"; const WASM_FILE: &str = &"res/cases/v1/inc_i32.wasm";
let program = DefaultProgramInstance::with_env_params( let program = DefaultProgramInstance::new().expect("Failed to instanciate program");
EnvParams {
total_stack: 128 * 1024,
total_memory: 2 * 1024 * 1024,
allow_memory_growth: false,
}).expect("Failed to instanciate program");
let module: Module = let module: Module =
deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer"); deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer");
@ -48,11 +43,7 @@ fn interpreter_accumulate_u8() {
const BUF: &[u8] = &[9,8,7,6,5,4,3,2,1]; const BUF: &[u8] = &[9,8,7,6,5,4,3,2,1];
// Declare the memory limits of the runtime-environment // Declare the memory limits of the runtime-environment
let program = DefaultProgramInstance::with_env_params(EnvParams { let program = DefaultProgramInstance::new().expect("Failed to instanciate program");
total_stack: 128 * 1024,
total_memory: 2 * 1024 * 1024,
allow_memory_growth: false,
}).expect("Failed to instanciate program");
// Load the module-structure from wasm-file and add to program // Load the module-structure from wasm-file and add to program
let module: Module = let module: Module =