Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/memory_creator.rs
1691 views
1
#[cfg(all(not(target_os = "windows"), not(miri)))]
2
mod not_for_windows {
3
use wasmtime::*;
4
5
use rustix::mm::{MapFlags, MprotectFlags, ProtFlags, mmap_anonymous, mprotect, munmap};
6
7
use std::ptr::null_mut;
8
use std::sync::{Arc, Mutex};
9
10
struct CustomMemory {
11
mem: usize,
12
size: usize,
13
guard_size: usize,
14
used_wasm_bytes: usize,
15
glob_bytes_counter: Arc<Mutex<usize>>,
16
}
17
18
impl CustomMemory {
19
unsafe fn new(minimum: usize, maximum: usize, glob_counter: Arc<Mutex<usize>>) -> Self {
20
let page_size = rustix::param::page_size();
21
let guard_size = page_size;
22
let size = maximum + guard_size;
23
// We rely on the Wasm page size being multiple of host page size.
24
assert_eq!(size % page_size, 0);
25
26
let mem = unsafe {
27
mmap_anonymous(null_mut(), size, ProtFlags::empty(), MapFlags::PRIVATE)
28
.expect("mmap failed")
29
};
30
31
// NOTE: mmap_anonymous returns zero initialized memory, which is relied upon by this
32
// API.
33
34
unsafe {
35
mprotect(mem, minimum, MprotectFlags::READ | MprotectFlags::WRITE)
36
.expect("mprotect failed");
37
}
38
*glob_counter.lock().unwrap() += minimum;
39
40
Self {
41
mem: mem as usize,
42
size,
43
guard_size,
44
used_wasm_bytes: minimum,
45
glob_bytes_counter: glob_counter,
46
}
47
}
48
}
49
50
impl Drop for CustomMemory {
51
fn drop(&mut self) {
52
*self.glob_bytes_counter.lock().unwrap() -= self.used_wasm_bytes;
53
unsafe { munmap(self.mem as *mut _, self.size).expect("munmap failed") };
54
}
55
}
56
57
unsafe impl LinearMemory for CustomMemory {
58
fn byte_size(&self) -> usize {
59
self.used_wasm_bytes
60
}
61
62
fn byte_capacity(&self) -> usize {
63
self.size - self.guard_size
64
}
65
66
fn grow_to(&mut self, new_size: usize) -> wasmtime::Result<()> {
67
println!("grow to {new_size:x}");
68
let delta = new_size - self.used_wasm_bytes;
69
unsafe {
70
let start = (self.mem as *mut u8).add(self.used_wasm_bytes) as _;
71
mprotect(start, delta, MprotectFlags::READ | MprotectFlags::WRITE)
72
.expect("mprotect failed");
73
}
74
75
*self.glob_bytes_counter.lock().unwrap() += delta;
76
self.used_wasm_bytes = new_size;
77
Ok(())
78
}
79
80
fn as_ptr(&self) -> *mut u8 {
81
self.mem as *mut u8
82
}
83
}
84
85
struct CustomMemoryCreator {
86
pub num_created_memories: Mutex<usize>,
87
pub num_total_bytes: Arc<Mutex<usize>>,
88
}
89
90
impl CustomMemoryCreator {
91
pub fn new() -> Self {
92
Self {
93
num_created_memories: Mutex::new(0),
94
num_total_bytes: Arc::new(Mutex::new(0)),
95
}
96
}
97
}
98
99
unsafe impl MemoryCreator for CustomMemoryCreator {
100
fn new_memory(
101
&self,
102
ty: MemoryType,
103
minimum: usize,
104
maximum: Option<usize>,
105
reserved_size: Option<usize>,
106
guard_size: usize,
107
) -> Result<Box<dyn LinearMemory>, String> {
108
assert_eq!(guard_size, 0);
109
assert_eq!(reserved_size, Some(0));
110
assert!(!ty.is_64());
111
unsafe {
112
// Cap the maximum at 10MiB to reduce the virtual memory
113
// allocated by this test to execute on 32-bit platforms.
114
let mem = Box::new(CustomMemory::new(
115
minimum,
116
maximum.unwrap_or(10 << 20),
117
self.num_total_bytes.clone(),
118
));
119
*self.num_created_memories.lock().unwrap() += 1;
120
Ok(mem)
121
}
122
}
123
}
124
125
fn config() -> (Store<()>, Arc<CustomMemoryCreator>) {
126
let mem_creator = Arc::new(CustomMemoryCreator::new());
127
let mut config = Config::new();
128
config
129
.with_host_memory(mem_creator.clone())
130
.memory_reservation(0)
131
.memory_guard_size(0);
132
(Store::new(&Engine::new(&config).unwrap(), ()), mem_creator)
133
}
134
135
#[test]
136
fn host_memory() -> anyhow::Result<()> {
137
let (mut store, mem_creator) = config();
138
let module = Module::new(
139
store.engine(),
140
r#"
141
(module
142
(memory (export "memory") 1)
143
)
144
"#,
145
)?;
146
Instance::new(&mut store, &module, &[])?;
147
148
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 1);
149
150
Ok(())
151
}
152
153
#[test]
154
fn host_memory_grow() -> anyhow::Result<()> {
155
let (mut store, mem_creator) = config();
156
let module = Module::new(
157
store.engine(),
158
r#"
159
(module
160
(func $f (drop (memory.grow (i32.const 1))))
161
(memory (export "memory") 1 2)
162
(start $f)
163
)
164
"#,
165
)?;
166
167
Instance::new(&mut store, &module, &[])?;
168
let instance2 = Instance::new(&mut store, &module, &[])?;
169
170
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 2);
171
172
assert_eq!(
173
instance2
174
.get_memory(&mut store, "memory")
175
.unwrap()
176
.size(&store),
177
2
178
);
179
180
// we take the lock outside the assert, so it won't get poisoned on assert failure
181
let tot_pages = *mem_creator.num_total_bytes.lock().unwrap();
182
assert_eq!(
183
tot_pages,
184
(4 * wasmtime_environ::Memory::DEFAULT_PAGE_SIZE) as usize
185
);
186
187
drop(store);
188
let tot_pages = *mem_creator.num_total_bytes.lock().unwrap();
189
assert_eq!(tot_pages, 0);
190
191
Ok(())
192
}
193
}
194
195