1use crate::{
2 func::{FuncBody, FuncInstance, FuncRef},
3 global::{GlobalInstance, GlobalRef},
4 host::Externals,
5 imports::ImportResolver,
6 memory::MemoryRef,
7 memory_units::Pages,
8 nan_preserving_float::{F32, F64},
9 runner::StackRecycler,
10 table::TableRef,
11 types::{GlobalDescriptor, MemoryDescriptor, TableDescriptor},
12 Error,
13 MemoryInstance,
14 Module,
15 RuntimeValue,
16 Signature,
17 TableInstance,
18 Trap,
19};
20use alloc::{
21 borrow::ToOwned,
22 collections::BTreeMap,
23 rc::Rc,
24 string::{String, ToString},
25 vec::Vec,
26};
27use casper_wasm::elements::{External, InitExpr, Instruction, Internal, ResizableLimits, Type};
28use core::{
29 cell::{Ref, RefCell},
30 fmt,
31};
32use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
33
34#[derive(Clone, Debug)]
48pub struct ModuleRef(pub(crate) Rc<ModuleInstance>);
49
50impl ::core::ops::Deref for ModuleRef {
51 type Target = ModuleInstance;
52 fn deref(&self) -> &ModuleInstance {
53 &self.0
54 }
55}
56
57pub enum ExternVal {
60 Func(FuncRef),
64 Table(TableRef),
68 Memory(MemoryRef),
72 Global(GlobalRef),
78}
79
80impl Clone for ExternVal {
81 fn clone(&self) -> Self {
82 match *self {
83 ExternVal::Func(ref func) => ExternVal::Func(func.clone()),
84 ExternVal::Table(ref table) => ExternVal::Table(table.clone()),
85 ExternVal::Memory(ref memory) => ExternVal::Memory(memory.clone()),
86 ExternVal::Global(ref global) => ExternVal::Global(global.clone()),
87 }
88 }
89}
90
91impl fmt::Debug for ExternVal {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 write!(
94 f,
95 "ExternVal {{ {} }}",
96 match *self {
97 ExternVal::Func(_) => "Func",
98 ExternVal::Table(_) => "Table",
99 ExternVal::Memory(_) => "Memory",
100 ExternVal::Global(_) => "Global",
101 }
102 )
103 }
104}
105
106impl ExternVal {
107 pub fn as_func(&self) -> Option<&FuncRef> {
110 match *self {
111 ExternVal::Func(ref func) => Some(func),
112 _ => None,
113 }
114 }
115
116 pub fn as_table(&self) -> Option<&TableRef> {
119 match *self {
120 ExternVal::Table(ref table) => Some(table),
121 _ => None,
122 }
123 }
124
125 pub fn as_memory(&self) -> Option<&MemoryRef> {
128 match *self {
129 ExternVal::Memory(ref memory) => Some(memory),
130 _ => None,
131 }
132 }
133
134 pub fn as_global(&self) -> Option<&GlobalRef> {
137 match *self {
138 ExternVal::Global(ref global) => Some(global),
139 _ => None,
140 }
141 }
142}
143
144#[derive(Debug)]
166pub struct ModuleInstance {
167 signatures: RefCell<Vec<Rc<Signature>>>,
168 tables: RefCell<Vec<TableRef>>,
169 funcs: RefCell<Vec<FuncRef>>,
170 memories: RefCell<Vec<MemoryRef>>,
171 globals: RefCell<Vec<GlobalRef>>,
172 exports: RefCell<BTreeMap<String, ExternVal>>,
173}
174
175impl ModuleInstance {
176 fn default() -> Self {
177 ModuleInstance {
178 funcs: RefCell::new(Vec::new()),
179 signatures: RefCell::new(Vec::new()),
180 tables: RefCell::new(Vec::new()),
181 memories: RefCell::new(Vec::new()),
182 globals: RefCell::new(Vec::new()),
183 exports: RefCell::new(BTreeMap::new()),
184 }
185 }
186
187 pub(crate) fn memory_by_index(&self, idx: u32) -> Option<MemoryRef> {
188 self.memories.borrow_mut().get(idx as usize).cloned()
189 }
190
191 pub(crate) fn table_by_index(&self, idx: u32) -> Option<TableRef> {
192 self.tables.borrow_mut().get(idx as usize).cloned()
193 }
194
195 pub(crate) fn global_by_index(&self, idx: u32) -> Option<GlobalRef> {
196 self.globals.borrow_mut().get(idx as usize).cloned()
197 }
198
199 pub(crate) fn func_by_index(&self, idx: u32) -> Option<FuncRef> {
200 self.funcs.borrow().get(idx as usize).cloned()
201 }
202
203 pub(crate) fn signature_by_index(&self, idx: u32) -> Option<Rc<Signature>> {
204 self.signatures.borrow().get(idx as usize).cloned()
205 }
206
207 fn push_func(&self, func: FuncRef) {
208 self.funcs.borrow_mut().push(func);
209 }
210
211 fn push_signature(&self, signature: Rc<Signature>) {
212 self.signatures.borrow_mut().push(signature)
213 }
214
215 fn push_memory(&self, memory: MemoryRef) {
216 self.memories.borrow_mut().push(memory)
217 }
218
219 fn push_table(&self, table: TableRef) {
220 self.tables.borrow_mut().push(table)
221 }
222
223 fn push_global(&self, global: GlobalRef) {
224 self.globals.borrow_mut().push(global)
225 }
226
227 pub fn globals(&self) -> Ref<Vec<GlobalRef>> {
230 self.globals.borrow()
231 }
232
233 fn insert_export<N: Into<String>>(&self, name: N, extern_val: ExternVal) {
234 self.exports.borrow_mut().insert(name.into(), extern_val);
235 }
236
237 fn alloc_module<'i, I: Iterator<Item = &'i ExternVal>>(
238 loaded_module: &Module,
239 extern_vals: I,
240 ) -> Result<ModuleRef, Error> {
241 let module = loaded_module.module();
242 let instance = ModuleRef(Rc::new(ModuleInstance::default()));
243
244 for Type::Function(ty) in module.type_section().map(|ts| ts.types()).unwrap_or(&[]) {
245 let signature = Rc::new(Signature::from_elements(ty));
246 instance.push_signature(signature);
247 }
248
249 {
250 let mut imports = module
251 .import_section()
252 .map(|is| is.entries())
253 .unwrap_or(&[])
254 .iter();
255 let mut extern_vals = extern_vals;
256 loop {
257 let (import, extern_val) = match (imports.next(), extern_vals.next()) {
261 (Some(import), Some(extern_val)) => (import, extern_val),
262 (None, None) => break,
263 (Some(_), None) | (None, Some(_)) => {
264 return Err(Error::Instantiation(
265 "extern_vals length is not equal to import section entries".to_owned(),
266 ));
267 }
268 };
269
270 match (import.external(), extern_val) {
271 (&External::Function(fn_type_idx), ExternVal::Func(func)) => {
272 let expected_fn_type = instance
273 .signature_by_index(fn_type_idx)
274 .expect("Due to validation function type should exists");
275 let actual_fn_type = func.signature();
276 if &*expected_fn_type != actual_fn_type {
277 return Err(Error::Instantiation(format!(
278 "Expected function with type {:?}, but actual type is {:?} for entry {}",
279 expected_fn_type,
280 actual_fn_type,
281 import.field(),
282 )));
283 }
284 instance.push_func(func.clone())
285 }
286 (External::Table(tt), ExternVal::Table(table)) => {
287 match_limits(table.limits(), tt.limits())?;
288 instance.push_table(table.clone());
289 }
290 (External::Memory(mt), ExternVal::Memory(memory)) => {
291 match_limits(memory.limits(), mt.limits())?;
292 instance.push_memory(memory.clone());
293 }
294 (External::Global(gl), ExternVal::Global(global)) => {
295 if gl.content_type() != global.elements_value_type() {
296 return Err(Error::Instantiation(format!(
297 "Expect global with {:?} type, but provided global with {:?} type",
298 gl.content_type(),
299 global.value_type(),
300 )));
301 }
302 instance.push_global(global.clone());
303 }
304 (expected_import, actual_extern_val) => {
305 return Err(Error::Instantiation(format!(
306 "Expected {:?} type, but provided {:?} extern_val",
307 expected_import, actual_extern_val
308 )));
309 }
310 }
311 }
312 }
313
314 let code = loaded_module.code();
315 {
316 let funcs = module
317 .function_section()
318 .map(|fs| fs.entries())
319 .unwrap_or(&[]);
320 let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]);
321 debug_assert!(
322 funcs.len() == bodies.len(),
323 "Due to validation func and body counts must match"
324 );
325
326 for (index, (ty, body)) in Iterator::zip(funcs.iter(), bodies.iter()).enumerate() {
327 let signature = instance
328 .signature_by_index(ty.type_ref())
329 .expect("Due to validation type should exists");
330 let code = code.get(index).expect(
331 "At func validation time labels are collected; Collected labels are added by index; qed",
332 ).clone();
333 let func_body = FuncBody {
334 locals: body.locals().to_vec(),
335 code,
336 };
337 let func_instance =
338 FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body);
339 instance.push_func(func_instance);
340 }
341 }
342
343 for table_type in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) {
344 let table =
345 TableInstance::alloc(table_type.limits().initial(), table_type.limits().maximum())?;
346 instance.push_table(table);
347 }
348
349 for memory_type in module
350 .memory_section()
351 .map(|ms| ms.entries())
352 .unwrap_or(&[])
353 {
354 let initial: Pages = Pages(memory_type.limits().initial() as usize);
355 let maximum: Option<Pages> = memory_type.limits().maximum().map(|m| Pages(m as usize));
356
357 let memory = MemoryInstance::alloc(initial, maximum)
358 .expect("Due to validation `initial` and `maximum` should be valid");
359 instance.push_memory(memory);
360 }
361
362 for global_entry in module
363 .global_section()
364 .map(|gs| gs.entries())
365 .unwrap_or(&[])
366 {
367 let init_val = eval_init_expr(global_entry.init_expr(), &instance);
368 let global = GlobalInstance::alloc(init_val, global_entry.global_type().is_mutable());
369 instance.push_global(global);
370 }
371
372 for export in module
373 .export_section()
374 .map(|es| es.entries())
375 .unwrap_or(&[])
376 {
377 let field = export.field();
378 let extern_val: ExternVal = match *export.internal() {
379 Internal::Function(idx) => {
380 let func = instance
381 .func_by_index(idx)
382 .expect("Due to validation func should exists");
383 ExternVal::Func(func)
384 }
385 Internal::Global(idx) => {
386 let global = instance
387 .global_by_index(idx)
388 .expect("Due to validation global should exists");
389 ExternVal::Global(global)
390 }
391 Internal::Memory(idx) => {
392 let memory = instance
393 .memory_by_index(idx)
394 .expect("Due to validation memory should exists");
395 ExternVal::Memory(memory)
396 }
397 Internal::Table(idx) => {
398 let table = instance
399 .table_by_index(idx)
400 .expect("Due to validation table should exists");
401 ExternVal::Table(table)
402 }
403 };
404 instance.insert_export(field, extern_val);
405 }
406
407 Ok(instance)
408 }
409
410 pub fn with_externvals<'a, 'i, I: Iterator<Item = &'i ExternVal>>(
417 loaded_module: &'a Module,
418 extern_vals: I,
419 ) -> Result<NotStartedModuleRef<'a>, Error> {
420 let module = loaded_module.module();
421
422 let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?;
423
424 for element_segment in module
425 .elements_section()
426 .map(|es| es.entries())
427 .unwrap_or(&[])
428 {
429 let offset = element_segment
430 .offset()
431 .as_ref()
432 .expect("passive segments are rejected due to validation");
433 let offset_val = match eval_init_expr(offset, &module_ref) {
434 RuntimeValue::I32(v) => v as u32,
435 _ => panic!("Due to validation elem segment offset should evaluate to i32"),
436 };
437
438 let table_inst = module_ref
439 .table_by_index(DEFAULT_TABLE_INDEX)
440 .expect("Due to validation default table should exists");
441
442 if offset_val as u64 + element_segment.members().len() as u64
445 > table_inst.current_size() as u64
446 {
447 return Err(Error::Instantiation(
448 "elements segment does not fit".to_string(),
449 ));
450 }
451
452 for (j, func_idx) in element_segment.members().iter().enumerate() {
453 let func = module_ref
454 .func_by_index(*func_idx)
455 .expect("Due to validation funcs from element segments should exists");
456
457 table_inst.set(offset_val + j as u32, Some(func))?;
458 }
459 }
460
461 for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) {
462 let offset = data_segment
463 .offset()
464 .as_ref()
465 .expect("passive segments are rejected due to validation");
466 let offset_val = match eval_init_expr(offset, &module_ref) {
467 RuntimeValue::I32(v) => v as u32,
468 _ => panic!("Due to validation data segment offset should evaluate to i32"),
469 };
470
471 let memory_inst = module_ref
472 .memory_by_index(DEFAULT_MEMORY_INDEX)
473 .expect("Due to validation default memory should exists");
474 memory_inst.set(offset_val, data_segment.value())?;
475 }
476
477 Ok(NotStartedModuleRef {
478 loaded_module,
479 instance: module_ref,
480 })
481 }
482
483 #[allow(clippy::new_ret_no_self)]
544 pub fn new<'m, I: ImportResolver>(
545 loaded_module: &'m Module,
546 imports: &I,
547 ) -> Result<NotStartedModuleRef<'m>, Error> {
548 let module = loaded_module.module();
549
550 let mut extern_vals = Vec::new();
551 for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) {
552 let module_name = import_entry.module();
553 let field_name = import_entry.field();
554 let extern_val = match *import_entry.external() {
555 External::Function(fn_ty_idx) => {
556 let types = module.type_section().map(|s| s.types()).unwrap_or(&[]);
557 let Type::Function(func_type) = types
558 .get(fn_ty_idx as usize)
559 .expect("Due to validation functions should have valid types");
560 let signature = Signature::from_elements(func_type);
561 let func = imports.resolve_func(module_name, field_name, &signature)?;
562 ExternVal::Func(func)
563 }
564 External::Table(ref table_type) => {
565 let table_descriptor = TableDescriptor::from_elements(table_type);
566 let table =
567 imports.resolve_table(module_name, field_name, &table_descriptor)?;
568 ExternVal::Table(table)
569 }
570 External::Memory(ref memory_type) => {
571 let memory_descriptor = MemoryDescriptor::from_elements(memory_type);
572 let memory =
573 imports.resolve_memory(module_name, field_name, &memory_descriptor)?;
574 ExternVal::Memory(memory)
575 }
576 External::Global(ref global_type) => {
577 let global_descriptor = GlobalDescriptor::from_elements(global_type);
578 let global =
579 imports.resolve_global(module_name, field_name, &global_descriptor)?;
580 ExternVal::Global(global)
581 }
582 };
583 extern_vals.push(extern_val);
584 }
585
586 Self::with_externvals(loaded_module, extern_vals.iter())
587 }
588
589 pub fn invoke_export<E: Externals>(
638 &self,
639 func_name: &str,
640 args: &[RuntimeValue],
641 externals: &mut E,
642 ) -> Result<Option<RuntimeValue>, Error> {
643 let func_instance = self.func_by_name(func_name)?;
644
645 FuncInstance::invoke(&func_instance, args, externals).map_err(Error::Trap)
646 }
647
648 pub fn invoke_export_with_stack<E: Externals>(
656 &self,
657 func_name: &str,
658 args: &[RuntimeValue],
659 externals: &mut E,
660 stack_recycler: &mut StackRecycler,
661 ) -> Result<Option<RuntimeValue>, Error> {
662 let func_instance = self.func_by_name(func_name)?;
663
664 FuncInstance::invoke_with_stack(&func_instance, args, externals, stack_recycler)
665 .map_err(Error::Trap)
666 }
667
668 fn func_by_name(&self, func_name: &str) -> Result<FuncRef, Error> {
669 let extern_val = self
670 .export_by_name(func_name)
671 .ok_or_else(|| Error::Function(format!("Module doesn't have export {}", func_name)))?;
672
673 match extern_val {
674 ExternVal::Func(func_instance) => Ok(func_instance),
675 unexpected => Err(Error::Function(format!(
676 "Export {} is not a function, but {:?}",
677 func_name, unexpected
678 ))),
679 }
680 }
681
682 pub fn export_by_name(&self, name: &str) -> Option<ExternVal> {
686 self.exports.borrow().get(name).cloned()
687 }
688}
689
690pub struct NotStartedModuleRef<'a> {
709 loaded_module: &'a Module,
710 instance: ModuleRef,
711}
712
713impl NotStartedModuleRef<'_> {
714 pub fn not_started_instance(&self) -> &ModuleRef {
724 &self.instance
725 }
726
727 pub fn run_start<E: Externals>(self, state: &mut E) -> Result<ModuleRef, Trap> {
733 if let Some(start_fn_idx) = self.loaded_module.module().start_section() {
734 let start_func = self
735 .instance
736 .func_by_index(start_fn_idx)
737 .expect("Due to validation start function should exists");
738 FuncInstance::invoke(&start_func, &[], state)?;
739 }
740 Ok(self.instance)
741 }
742
743 pub fn run_start_with_stack<E: Externals>(
749 self,
750 state: &mut E,
751 stack_recycler: &mut StackRecycler,
752 ) -> Result<ModuleRef, Trap> {
753 if let Some(start_fn_idx) = self.loaded_module.module().start_section() {
754 let start_func = self
755 .instance
756 .func_by_index(start_fn_idx)
757 .expect("Due to validation start function should exists");
758 FuncInstance::invoke_with_stack(&start_func, &[], state, stack_recycler)?;
759 }
760 Ok(self.instance)
761 }
762
763 pub fn assert_no_start(self) -> ModuleRef {
769 assert!(
770 self.loaded_module.module().start_section().is_none(),
771 "assert_no_start called on module with `start` function"
772 );
773 self.instance
774 }
775
776 pub fn has_start(&self) -> bool {
780 self.loaded_module.module().start_section().is_some()
781 }
782}
783
784fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue {
785 let code = init_expr.code();
786 debug_assert!(
787 code.len() == 2,
788 "Due to validation `code`.len() should be 2"
789 );
790 match code[0] {
791 Instruction::I32Const(v) => v.into(),
792 Instruction::I64Const(v) => v.into(),
793 Instruction::F32Const(v) => F32::from_bits(v).into(),
794 Instruction::F64Const(v) => F64::from_bits(v).into(),
795 Instruction::GetGlobal(idx) => {
796 let global = module
797 .global_by_index(idx)
798 .expect("Due to validation global should exists in module");
799 global.get()
800 }
801 _ => panic!("Due to validation init should be a const expr"),
802 }
803}
804
805fn match_limits(l1: &ResizableLimits, l2: &ResizableLimits) -> Result<(), Error> {
806 if l1.initial() < l2.initial() {
807 return Err(Error::Instantiation(format!(
808 "trying to import with limits l1.initial={} and l2.initial={}",
809 l1.initial(),
810 l2.initial()
811 )));
812 }
813
814 match (l1.maximum(), l2.maximum()) {
815 (_, None) => (),
816 (Some(m1), Some(m2)) if m1 <= m2 => (),
817 _ => {
818 return Err(Error::Instantiation(format!(
819 "trying to import with limits l1.max={:?} and l2.max={:?}",
820 l1.maximum(),
821 l2.maximum()
822 )));
823 }
824 }
825
826 Ok(())
827}
828
829pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
830 if let Some(maximum) = limits.maximum() {
831 if maximum < limits.initial() {
832 return Err(Error::Instantiation(format!(
833 "maximum limit {} is less than minimum {}",
834 maximum,
835 limits.initial()
836 )));
837 }
838 }
839
840 Ok(())
841}
842
843#[cfg(test)]
844mod tests {
845 use super::{ExternVal, ModuleInstance};
846 use crate::{func::FuncInstance, imports::ImportsBuilder, types::Signature, Module, ValueType};
847
848 fn parse_wat(source: &str) -> Module {
849 let wasm_binary = wat::parse_str(source).expect("Failed to parse wat source");
850 Module::from_buffer(wasm_binary).expect("Failed to load parsed module")
851 }
852
853 #[should_panic]
854 #[test]
855 fn assert_no_start_panics_on_module_with_start() {
856 let module_with_start = parse_wat(
857 r#"
858 (module
859 (func $f)
860 (start $f))
861 "#,
862 );
863 let module = ModuleInstance::new(&module_with_start, &ImportsBuilder::default()).unwrap();
864 assert!(!module.has_start());
865 module.assert_no_start();
866 }
867
868 #[test]
869 fn imports_provided_by_externvals() {
870 let module_with_single_import = parse_wat(
871 r#"
872 (module
873 (import "foo" "bar" (func))
874 )
875 "#,
876 );
877
878 assert!(ModuleInstance::with_externvals(
879 &module_with_single_import,
880 [ExternVal::Func(FuncInstance::alloc_host(
881 Signature::new(&[][..], None),
882 0
883 ),)]
884 .iter(),
885 )
886 .is_ok());
887
888 assert!(ModuleInstance::with_externvals(
890 &module_with_single_import,
891 [
892 ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)),
893 ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)),
894 ]
895 .iter(),
896 )
897 .is_err());
898
899 assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(),).is_err());
901
902 assert!(ModuleInstance::with_externvals(
904 &module_with_single_import,
905 [ExternVal::Func(FuncInstance::alloc_host(
906 Signature::new(&[][..], Some(ValueType::I32)),
907 0
908 ),)]
909 .iter(),
910 )
911 .is_err());
912 }
913}