inkpad_executor/
memory.rs

1//! Inkpad executor memory
2#[cfg(not(feature = "std"))]
3use crate::wasmi as e;
4#[cfg(feature = "std")]
5use crate::wasmtime as e;
6use crate::{derive, Result};
7use core::ops;
8use parity_wasm::elements::{External, Module};
9
10const IMPORT_MODULE_MEMORY: &str = "env";
11
12/// WASM executor liner memory
13#[derive(Clone)]
14pub struct Memory(pub e::Memory);
15
16impl ops::Deref for Memory {
17    type Target = e::Memory;
18
19    fn deref(&self) -> &e::Memory {
20        &self.0
21    }
22}
23
24impl Memory {
25    /// New liner memory
26    pub fn new(initial: u32, maximum: Option<u32>) -> Result<Self> {
27        Ok(Self(<e::Memory as derive::Memory>::new(initial, maximum)?))
28    }
29
30    /// Read a memory area at the address `ptr` with the size of the provided slice `buf`.
31    pub fn get(&self, ptr: u32, buf: &mut [u8]) -> Result<()> {
32        derive::Memory::get(&self.0, ptr, buf)
33    }
34
35    /// Write a memory area at the address `ptr` with contents of the provided slice `buf`.
36    pub fn set(&self, ptr: u32, value: &[u8]) -> Result<()> {
37        derive::Memory::set(&self.0, ptr, value)
38    }
39}
40
41/// Scan an import section if any.
42///
43/// This accomplishes two tasks:
44///
45/// - checks any imported function against defined host functions set, incl.
46///   their signatures.
47/// - if there is a memory import, returns it's descriptor
48/// `import_fn_banlist`: list of function names that are disallowed to be imported
49pub fn scan_imports(module: &Module) -> core::result::Result<(u32, Option<u32>), &'static str> {
50    let import_entries = module
51        .import_section()
52        .map(|is| is.entries())
53        .unwrap_or(&[]);
54
55    let mut range = None;
56    for import in import_entries {
57        match import.external() {
58            External::Table(_) => return Err("Cannot import tables"),
59            External::Global(_) => return Err("Cannot import globals"),
60            External::Function(ref type_idx) => type_idx,
61            External::Memory(ref memory_type) => {
62                if import.module() != IMPORT_MODULE_MEMORY {
63                    return Err("Invalid module for imported memory");
64                }
65                if import.field() != "memory" {
66                    return Err("Memory import must have the field name 'memory'");
67                }
68                if range.is_some() {
69                    return Err("Multiple memory imports defined");
70                }
71
72                let limits = memory_type.limits();
73                range = Some((limits.initial() as u32, limits.maximum().map(|v| v as u32)));
74                continue;
75            }
76        };
77    }
78
79    if let Some(limit) = range {
80        Ok(limit)
81    } else {
82        Ok((0, None))
83    }
84}