pchain_runtime/wasmer/
custom_tunables.rs

1/*
2    Copyright © 2023, ParallelChain Lab
3    Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
4*/
5
6//! Defines structs that are used as configuration of wasmer store for limiting the memory
7//! used for wasm module instantiation.
8
9use loupe::MemoryUsage;
10use std::ptr::NonNull;
11use std::sync::Arc;
12use wasmer::{
13    vm::{self, MemoryError, MemoryStyle, TableStyle, VMMemoryDefinition, VMTableDefinition},
14    MemoryType, Pages, TableType, Tunables,
15};
16
17/// CustomTunables allows the setting of an upper limit on the guest memory of the VM.
18/// CustomTunables also conists of a base Tunables attribute which all the existing logic is delegated to after
19/// guest memory adjustment  
20#[derive(MemoryUsage)]
21pub struct CustomTunables<T: Tunables> {
22    /// maximum allowable guest memory (in WASM pages, each approximately 65KiB in size)
23    limit: Pages,
24
25    /// base implementation we delegate all the logic to after guest memory adjustment
26    base: T,
27}
28
29impl<T: Tunables> Tunables for CustomTunables<T> {
30    /// `memory_style` is used to construct a WebAssembly `MemoryStyle` for the provided `MemoryType` using base tunables
31    /// For more information on `memory_style`: See <https://github.com/wasmerio/wasmer/blob/master/examples/tunables_limit_memory.rs>
32    fn memory_style(&self, memory: &MemoryType) -> MemoryStyle {
33        let adjusted = self.adjust_memory(memory);
34        self.base.memory_style(&adjusted)
35    }
36
37    /// `table_style` is used to construct a WebAssembly `TableStyle` for the provided `TableType` using base tunables
38    /// For more information on `table_style`: See <https://github.com/wasmerio/wasmer/blob/master/examples/tunables_limit_memory.rs>
39    fn table_style(&self, table: &TableType) -> TableStyle {
40        self.base.table_style(table)
41    }
42
43    /// `create_host_memory` creates memory owned by the host given a WebAssembly `MemoryType` and a `MemoryStyle`
44    /// The requested memory type is validated, adjusted to the limited and then passed to base tunables
45    /// For more information on `create_host_memory`: See <https://github.com/wasmerio/wasmer/blob/master/examples/tunables_limit_memory.rs>
46    fn create_host_memory(
47        &self,
48        ty: &MemoryType,
49        style: &MemoryStyle,
50    ) -> Result<Arc<dyn vm::Memory>, MemoryError> {
51        let adjusted = self.adjust_memory(ty);
52        self.validate_memory(&adjusted)?;
53        self.base.create_host_memory(&adjusted, style)
54    }
55
56    /// `create_vm_memory` creates memory owned by the VM given a WebAssembly `MemoryType` and a `MemoryStyle`.
57    /// For more information on `create_vm_memory`: See <https://github.com/wasmerio/wasmer/blob/master/examples/tunables_limit_memory.rs>
58    unsafe fn create_vm_memory(
59        &self,
60        ty: &MemoryType,
61        style: &MemoryStyle,
62        vm_definition_location: NonNull<VMMemoryDefinition>,
63    ) -> Result<Arc<dyn vm::Memory>, MemoryError> {
64        let adjusted = self.adjust_memory(ty);
65        self.validate_memory(&adjusted)?;
66        self.base
67            .create_vm_memory(&adjusted, style, vm_definition_location)
68    }
69
70    // `create_host_table` creates a table owned by the host given a WebAssembly `TableType` and a `TableStyle`.
71    // For more information on `create_host_table`: See <https://github.com/wasmerio/wasmer/blob/master/examples/tunables_limit_memory.rs>
72    fn create_host_table(
73        &self,
74        ty: &TableType,
75        style: &TableStyle,
76    ) -> Result<Arc<dyn vm::Table>, String> {
77        self.base.create_host_table(ty, style)
78    }
79
80    // `create_vm_table` creates a table owned by the VM given a WebAssembly `TableType` and a `TableStyle`.
81    // For more information on `create_vm_table`: See <https://github.com/wasmerio/wasmer/blob/master/examples/tunables_limit_memory.rs>
82    unsafe fn create_vm_table(
83        &self,
84        ty: &TableType,
85        style: &TableStyle,
86        vm_definition_location: NonNull<VMTableDefinition>,
87    ) -> Result<Arc<dyn vm::Table>, String> {
88        self.base.create_vm_table(ty, style, vm_definition_location)
89    }
90}
91
92impl<T: Tunables> CustomTunables<T> {
93    pub fn new(base: T, limit: Pages) -> Self {
94        Self { limit, base }
95    }
96
97    // `adjust_memory` accepts an input memory descriptor requested by guest and sets
98    // a maximum limit for the descriptor, if not assigned earlier.
99    fn adjust_memory(&self, requested: &MemoryType) -> MemoryType {
100        let mut adjusted = *requested;
101        if requested.maximum.is_none() {
102            adjusted.maximum = Some(self.limit);
103        }
104        adjusted
105    }
106
107    // `validate_memory` ensures that the number of pages in the memory descriptor does not
108    // exceed the preset memory limit. It should be called in sequence after `adjust_memory`.
109    fn validate_memory(&self, ty: &MemoryType) -> Result<(), MemoryError> {
110        if ty.minimum > self.limit {
111            return Err(MemoryError::Generic(
112                "Minimum limit exceeds the allowed memory limit".to_string(),
113            ));
114        }
115
116        if let Some(max) = ty.maximum {
117            if max > self.limit {
118                return Err(MemoryError::Generic(
119                    "Maximum limit exceeds the allowed memory limit".to_string(),
120                ));
121            }
122        } else {
123            return Err(MemoryError::Generic("Maximum limit unset".to_string()));
124        }
125
126        Ok(())
127    }
128}