1 use crate::prelude::*;
2 use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator};
3 use crate::runtime::vm::imports::Imports;
4 use crate::runtime::vm::instance::{Instance, InstanceHandle};
5 use crate::runtime::vm::memory::Memory;
6 use crate::runtime::vm::mpk::ProtectionKey;
7 use crate::runtime::vm::table::Table;
8 use crate::runtime::vm::{CompiledModuleId, ModuleRuntimeInfo, VMFuncRef, VMGcRef, VMStore};
9 use crate::store::{AutoAssertNoGc, StoreOpaque};
10 use crate::vm::VMGlobalDefinition;
11 use core::ptr::NonNull;
12 use core::{any::Any, mem, ptr};
13 use wasmtime_environ::{
14     DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization,
15     MemoryInitializer, Module, PrimaryMap, SizeOverflow, TableInitialValue, Trap, Tunables,
16     VMOffsets, WasmHeapTopType,
17 };
18 
19 #[cfg(feature = "gc")]
20 use crate::runtime::vm::{GcHeap, GcRuntime};
21 
22 #[cfg(feature = "component-model")]
23 use wasmtime_environ::{
24     component::{Component, VMComponentOffsets},
25     StaticModuleIndex,
26 };
27 
28 mod on_demand;
29 pub use self::on_demand::OnDemandInstanceAllocator;
30 
31 #[cfg(feature = "pooling-allocator")]
32 mod pooling;
33 #[cfg(feature = "pooling-allocator")]
34 pub use self::pooling::{
35     InstanceLimits, PoolConcurrencyLimitError, PoolingInstanceAllocator,
36     PoolingInstanceAllocatorConfig,
37 };
38 
39 /// Represents a request for a new runtime instance.
40 pub struct InstanceAllocationRequest<'a> {
41     /// The info related to the compiled version of this module,
42     /// needed for instantiation: function metadata, JIT code
43     /// addresses, precomputed images for lazy memory and table
44     /// initialization, and the like. This Arc is cloned and held for
45     /// the lifetime of the instance.
46     pub runtime_info: &'a ModuleRuntimeInfo,
47 
48     /// The imports to use for the instantiation.
49     pub imports: Imports<'a>,
50 
51     /// The host state to associate with the instance.
52     pub host_state: Box<dyn Any + Send + Sync>,
53 
54     /// A pointer to the "store" for this instance to be allocated. The store
55     /// correlates with the `Store` in wasmtime itself, and lots of contextual
56     /// information about the execution of wasm can be learned through the
57     /// store.
58     ///
59     /// Note that this is a raw pointer and has a static lifetime, both of which
60     /// are a bit of a lie. This is done purely so a store can learn about
61     /// itself when it gets called as a host function, and additionally so this
62     /// runtime can access internals as necessary (such as the
63     /// VMExternRefActivationsTable or the resource limiter methods).
64     ///
65     /// Note that this ends up being a self-pointer to the instance when stored.
66     /// The reason is that the instance itself is then stored within the store.
67     /// We use a number of `PhantomPinned` declarations to indicate this to the
68     /// compiler. More info on this in `wasmtime/src/store.rs`
69     pub store: StorePtr,
70 
71     /// Indicates '--wmemcheck' flag.
72     #[cfg_attr(not(feature = "wmemcheck"), allow(dead_code))]
73     pub wmemcheck: bool,
74 
75     /// Request that the instance's memories be protected by a specific
76     /// protection key.
77     pub pkey: Option<ProtectionKey>,
78 
79     /// Tunable configuration options the engine is using.
80     pub tunables: &'a Tunables,
81 }
82 
83 /// A pointer to a Store. This Option<*mut dyn Store> is wrapped in a struct
84 /// so that the function to create a &mut dyn Store is a method on a member of
85 /// InstanceAllocationRequest, rather than on a &mut InstanceAllocationRequest
86 /// itself, because several use-sites require a split mut borrow on the
87 /// InstanceAllocationRequest.
88 pub struct StorePtr(Option<NonNull<dyn VMStore>>);
89 
90 impl StorePtr {
91     /// A pointer to no Store.
92     pub fn empty() -> Self {
93         Self(None)
94     }
95 
96     /// A pointer to a Store.
97     pub fn new(ptr: NonNull<dyn VMStore>) -> Self {
98         Self(Some(ptr))
99     }
100 
101     /// The raw contents of this struct
102     pub fn as_raw(&self) -> Option<NonNull<dyn VMStore>> {
103         self.0
104     }
105 
106     /// Use the StorePtr as a mut ref to the Store.
107     ///
108     /// Safety: must not be used outside the original lifetime of the borrow.
109     pub(crate) unsafe fn get(&mut self) -> Option<&mut dyn VMStore> {
110         let ptr = self.0?.as_mut();
111         Some(ptr)
112     }
113 }
114 
115 /// The index of a memory allocation within an `InstanceAllocator`.
116 #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
117 pub struct MemoryAllocationIndex(u32);
118 
119 impl Default for MemoryAllocationIndex {
120     fn default() -> Self {
121         // A default `MemoryAllocationIndex` that can be used with
122         // `InstanceAllocator`s that don't actually need indices.
123         MemoryAllocationIndex(u32::MAX)
124     }
125 }
126 
127 impl MemoryAllocationIndex {
128     /// Get the underlying index of this `MemoryAllocationIndex`.
129     pub fn index(&self) -> usize {
130         self.0 as usize
131     }
132 }
133 
134 /// The index of a table allocation within an `InstanceAllocator`.
135 #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
136 pub struct TableAllocationIndex(u32);
137 
138 impl Default for TableAllocationIndex {
139     fn default() -> Self {
140         // A default `TableAllocationIndex` that can be used with
141         // `InstanceAllocator`s that don't actually need indices.
142         TableAllocationIndex(u32::MAX)
143     }
144 }
145 
146 impl TableAllocationIndex {
147     /// Get the underlying index of this `TableAllocationIndex`.
148     pub fn index(&self) -> usize {
149         self.0 as usize
150     }
151 }
152 
153 /// The index of a table allocation within an `InstanceAllocator`.
154 #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
155 pub struct GcHeapAllocationIndex(u32);
156 
157 impl Default for GcHeapAllocationIndex {
158     fn default() -> Self {
159         // A default `GcHeapAllocationIndex` that can be used with
160         // `InstanceAllocator`s that don't actually need indices.
161         GcHeapAllocationIndex(u32::MAX)
162     }
163 }
164 
165 impl GcHeapAllocationIndex {
166     /// Get the underlying index of this `GcHeapAllocationIndex`.
167     pub fn index(&self) -> usize {
168         self.0 as usize
169     }
170 }
171 
172 /// Trait that represents the hooks needed to implement an instance allocator.
173 ///
174 /// Implement this trait when implementing new instance allocators, but don't
175 /// use this trait when you need an instance allocator. Instead use the
176 /// `InstanceAllocator` trait for that, which has additional helper methods and
177 /// a blanket implementation for all types that implement this trait.
178 ///
179 /// # Safety
180 ///
181 /// This trait is unsafe as it requires knowledge of Wasmtime's runtime
182 /// internals to implement correctly.
183 pub unsafe trait InstanceAllocatorImpl {
184     /// Validate whether a component (including all of its contained core
185     /// modules) is allocatable by this instance allocator.
186     #[cfg(feature = "component-model")]
187     fn validate_component_impl<'a>(
188         &self,
189         component: &Component,
190         offsets: &VMComponentOffsets<HostPtr>,
191         get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module,
192     ) -> Result<()>;
193 
194     /// Validate whether a module is allocatable by this instance allocator.
195     fn validate_module_impl(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()>;
196 
197     /// Increment the count of concurrent component instances that are currently
198     /// allocated, if applicable.
199     ///
200     /// Not all instance allocators will have limits for the maximum number of
201     /// concurrent component instances that can be live at the same time, and
202     /// these allocators may implement this method with a no-op.
203     //
204     // Note: It would be nice to have an associated type that on construction
205     // does the increment and on drop does the decrement but there are two
206     // problems with this:
207     //
208     // 1. This trait's implementations are always used as trait objects, and
209     //    associated types are not object safe.
210     //
211     // 2. We would want a parameterized `Drop` implementation so that we could
212     //    pass in the `InstanceAllocatorImpl` on drop, but this doesn't exist in
213     //    Rust. Therefore, we would be forced to add reference counting and
214     //    stuff like that to keep a handle on the instance allocator from this
215     //    theoretical type. That's a bummer.
216     fn increment_component_instance_count(&self) -> Result<()>;
217 
218     /// The dual of `increment_component_instance_count`.
219     fn decrement_component_instance_count(&self);
220 
221     /// Increment the count of concurrent core module instances that are
222     /// currently allocated, if applicable.
223     ///
224     /// Not all instance allocators will have limits for the maximum number of
225     /// concurrent core module instances that can be live at the same time, and
226     /// these allocators may implement this method with a no-op.
227     fn increment_core_instance_count(&self) -> Result<()>;
228 
229     /// The dual of `increment_core_instance_count`.
230     fn decrement_core_instance_count(&self);
231 
232     /// Allocate a memory for an instance.
233     ///
234     /// # Unsafety
235     ///
236     /// The memory and its associated module must have already been validated by
237     /// `Self::validate_module` and passed that validation.
238     unsafe fn allocate_memory(
239         &self,
240         request: &mut InstanceAllocationRequest,
241         ty: &wasmtime_environ::Memory,
242         tunables: &Tunables,
243         memory_index: DefinedMemoryIndex,
244     ) -> Result<(MemoryAllocationIndex, Memory)>;
245 
246     /// Deallocate an instance's previously allocated memory.
247     ///
248     /// # Unsafety
249     ///
250     /// The memory must have previously been allocated by
251     /// `Self::allocate_memory`, be at the given index, and must currently be
252     /// allocated. It must never be used again.
253     unsafe fn deallocate_memory(
254         &self,
255         memory_index: DefinedMemoryIndex,
256         allocation_index: MemoryAllocationIndex,
257         memory: Memory,
258     );
259 
260     /// Allocate a table for an instance.
261     ///
262     /// # Unsafety
263     ///
264     /// The table and its associated module must have already been validated by
265     /// `Self::validate_module` and passed that validation.
266     unsafe fn allocate_table(
267         &self,
268         req: &mut InstanceAllocationRequest,
269         table: &wasmtime_environ::Table,
270         tunables: &Tunables,
271         table_index: DefinedTableIndex,
272     ) -> Result<(TableAllocationIndex, Table)>;
273 
274     /// Deallocate an instance's previously allocated table.
275     ///
276     /// # Unsafety
277     ///
278     /// The table must have previously been allocated by `Self::allocate_table`,
279     /// be at the given index, and must currently be allocated. It must never be
280     /// used again.
281     unsafe fn deallocate_table(
282         &self,
283         table_index: DefinedTableIndex,
284         allocation_index: TableAllocationIndex,
285         table: Table,
286     );
287 
288     /// Allocates a fiber stack for calling async functions on.
289     #[cfg(feature = "async")]
290     fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>;
291 
292     /// Deallocates a fiber stack that was previously allocated with
293     /// `allocate_fiber_stack`.
294     ///
295     /// # Safety
296     ///
297     /// The provided stack is required to have been allocated with
298     /// `allocate_fiber_stack`.
299     #[cfg(feature = "async")]
300     unsafe fn deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack);
301 
302     /// Allocate a GC heap for allocating Wasm GC objects within.
303     #[cfg(feature = "gc")]
304     fn allocate_gc_heap(
305         &self,
306         gc_runtime: &dyn GcRuntime,
307     ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)>;
308 
309     /// Deallocate a GC heap that was previously allocated with
310     /// `allocate_gc_heap`.
311     #[cfg(feature = "gc")]
312     fn deallocate_gc_heap(&self, allocation_index: GcHeapAllocationIndex, gc_heap: Box<dyn GcHeap>);
313 
314     /// Purges all lingering resources related to `module` from within this
315     /// allocator.
316     ///
317     /// Primarily present for the pooling allocator to remove mappings of
318     /// this module from slots in linear memory.
319     fn purge_module(&self, module: CompiledModuleId);
320 
321     /// Use the next available protection key.
322     ///
323     /// The pooling allocator can use memory protection keys (MPK) for
324     /// compressing the guard regions protecting against OOB. Each
325     /// pool-allocated store needs its own key.
326     fn next_available_pkey(&self) -> Option<ProtectionKey>;
327 
328     /// Restrict access to memory regions protected by `pkey`.
329     ///
330     /// This is useful for the pooling allocator, which can use memory
331     /// protection keys (MPK). Note: this may still allow access to other
332     /// protection keys, such as the default kernel key; see implementations of
333     /// this.
334     fn restrict_to_pkey(&self, pkey: ProtectionKey);
335 
336     /// Allow access to memory regions protected by any protection key.
337     fn allow_all_pkeys(&self);
338 }
339 
340 /// A thing that can allocate instances.
341 ///
342 /// Don't implement this trait directly, instead implement
343 /// `InstanceAllocatorImpl` and you'll get this trait for free via a blanket
344 /// impl.
345 pub trait InstanceAllocator: InstanceAllocatorImpl {
346     /// Validate whether a component (including all of its contained core
347     /// modules) is allocatable with this instance allocator.
348     #[cfg(feature = "component-model")]
349     fn validate_component<'a>(
350         &self,
351         component: &Component,
352         offsets: &VMComponentOffsets<HostPtr>,
353         get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module,
354     ) -> Result<()> {
355         InstanceAllocatorImpl::validate_component_impl(self, component, offsets, get_module)
356     }
357 
358     /// Validate whether a core module is allocatable with this instance
359     /// allocator.
360     fn validate_module(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()> {
361         InstanceAllocatorImpl::validate_module_impl(self, module, offsets)
362     }
363 
364     /// Allocates a fresh `InstanceHandle` for the `req` given.
365     ///
366     /// This will allocate memories and tables internally from this allocator
367     /// and weave that altogether into a final and complete `InstanceHandle`
368     /// ready to be registered with a store.
369     ///
370     /// Note that the returned instance must still have `.initialize(..)` called
371     /// on it to complete the instantiation process.
372     ///
373     /// # Unsafety
374     ///
375     /// The request's associated module, memories, tables, and vmctx must have
376     /// already have been validated by `Self::validate_module`.
377     unsafe fn allocate_module(
378         &self,
379         mut request: InstanceAllocationRequest,
380     ) -> Result<InstanceHandle> {
381         let module = request.runtime_info.env_module();
382 
383         #[cfg(debug_assertions)]
384         InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets())
385             .expect("module should have already been validated before allocation");
386 
387         self.increment_core_instance_count()?;
388 
389         let num_defined_memories = module.num_defined_memories();
390         let mut memories = PrimaryMap::with_capacity(num_defined_memories);
391 
392         let num_defined_tables = module.num_defined_tables();
393         let mut tables = PrimaryMap::with_capacity(num_defined_tables);
394 
395         match (|| {
396             self.allocate_memories(&mut request, &mut memories)?;
397             self.allocate_tables(&mut request, &mut tables)?;
398             Ok(())
399         })() {
400             Ok(_) => Ok(Instance::new(request, memories, tables, &module.memories)),
401             Err(e) => {
402                 self.deallocate_memories(&mut memories);
403                 self.deallocate_tables(&mut tables);
404                 self.decrement_core_instance_count();
405                 Err(e)
406             }
407         }
408     }
409 
410     /// Deallocates the provided instance.
411     ///
412     /// This will null-out the pointer within `handle` and otherwise reclaim
413     /// resources such as tables, memories, and the instance memory itself.
414     ///
415     /// # Unsafety
416     ///
417     /// The instance must have previously been allocated by `Self::allocate`.
418     unsafe fn deallocate_module(&self, handle: &mut InstanceHandle) {
419         self.deallocate_memories(&mut handle.instance_mut().memories);
420         self.deallocate_tables(&mut handle.instance_mut().tables);
421 
422         let layout = Instance::alloc_layout(handle.instance().offsets());
423         let ptr = handle.instance.take().unwrap();
424         ptr::drop_in_place(ptr.as_ptr());
425         alloc::alloc::dealloc(ptr.as_ptr().cast(), layout);
426 
427         self.decrement_core_instance_count();
428     }
429 
430     /// Allocate the memories for the given instance allocation request, pushing
431     /// them into `memories`.
432     ///
433     /// # Unsafety
434     ///
435     /// The request's associated module and memories must have previously been
436     /// validated by `Self::validate_module`.
437     unsafe fn allocate_memories(
438         &self,
439         request: &mut InstanceAllocationRequest,
440         memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
441     ) -> Result<()> {
442         let module = request.runtime_info.env_module();
443 
444         #[cfg(debug_assertions)]
445         InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets())
446             .expect("module should have already been validated before allocation");
447 
448         for (memory_index, ty) in module.memories.iter().skip(module.num_imported_memories) {
449             let memory_index = module
450                 .defined_memory_index(memory_index)
451                 .expect("should be a defined memory since we skipped imported ones");
452 
453             memories.push(self.allocate_memory(request, ty, request.tunables, memory_index)?);
454         }
455 
456         Ok(())
457     }
458 
459     /// Deallocate all the memories in the given primary map.
460     ///
461     /// # Unsafety
462     ///
463     /// The memories must have previously been allocated by
464     /// `Self::allocate_memories`.
465     unsafe fn deallocate_memories(
466         &self,
467         memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
468     ) {
469         for (memory_index, (allocation_index, memory)) in mem::take(memories) {
470             // Because deallocating memory is infallible, we don't need to worry
471             // about leaking subsequent memories if the first memory failed to
472             // deallocate. If deallocating memory ever becomes fallible, we will
473             // need to be careful here!
474             self.deallocate_memory(memory_index, allocation_index, memory);
475         }
476     }
477 
478     /// Allocate tables for the given instance allocation request, pushing them
479     /// into `tables`.
480     ///
481     /// # Unsafety
482     ///
483     /// The request's associated module and tables must have previously been
484     /// validated by `Self::validate_module`.
485     unsafe fn allocate_tables(
486         &self,
487         request: &mut InstanceAllocationRequest,
488         tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
489     ) -> Result<()> {
490         let module = request.runtime_info.env_module();
491 
492         #[cfg(debug_assertions)]
493         InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets())
494             .expect("module should have already been validated before allocation");
495 
496         for (index, table) in module.tables.iter().skip(module.num_imported_tables) {
497             let def_index = module
498                 .defined_table_index(index)
499                 .expect("should be a defined table since we skipped imported ones");
500 
501             tables.push(self.allocate_table(request, table, request.tunables, def_index)?);
502         }
503 
504         Ok(())
505     }
506 
507     /// Deallocate all the tables in the given primary map.
508     ///
509     /// # Unsafety
510     ///
511     /// The tables must have previously been allocated by
512     /// `Self::allocate_tables`.
513     unsafe fn deallocate_tables(
514         &self,
515         tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
516     ) {
517         for (table_index, (allocation_index, table)) in mem::take(tables) {
518             self.deallocate_table(table_index, allocation_index, table);
519         }
520     }
521 }
522 
523 // Every `InstanceAllocatorImpl` is an `InstanceAllocator` when used
524 // correctly. Also, no one is allowed to override this trait's methods, they
525 // must use the defaults. This blanket impl provides both of those things.
526 impl<T: InstanceAllocatorImpl> InstanceAllocator for T {}
527 
528 fn check_table_init_bounds(
529     store: &mut StoreOpaque,
530     instance: &mut Instance,
531     module: &Module,
532 ) -> Result<()> {
533     let mut const_evaluator = ConstExprEvaluator::default();
534 
535     for segment in module.table_initialization.segments.iter() {
536         let table = unsafe { &*instance.get_table(segment.table_index) };
537         let mut context = ConstEvalContext::new(instance);
538         let start = unsafe {
539             const_evaluator
540                 .eval(store, &mut context, &segment.offset)
541                 .expect("const expression should be valid")
542         };
543         let start = usize::try_from(start.get_u32()).unwrap();
544         let end = start.checked_add(usize::try_from(segment.elements.len()).unwrap());
545 
546         match end {
547             Some(end) if end <= table.size() => {
548                 // Initializer is in bounds
549             }
550             _ => {
551                 bail!("table out of bounds: elements segment does not fit")
552             }
553         }
554     }
555 
556     Ok(())
557 }
558 
559 fn initialize_tables(
560     store: &mut StoreOpaque,
561     context: &mut ConstEvalContext<'_>,
562     const_evaluator: &mut ConstExprEvaluator,
563     module: &Module,
564 ) -> Result<()> {
565     for (table, init) in module.table_initialization.initial_values.iter() {
566         match init {
567             // Tables are always initially null-initialized at this time
568             TableInitialValue::Null { precomputed: _ } => {}
569 
570             TableInitialValue::Expr(expr) => {
571                 let raw = unsafe {
572                     const_evaluator
573                         .eval(store, context, expr)
574                         .expect("const expression should be valid")
575                 };
576                 let idx = module.table_index(table);
577                 let table = unsafe { context.instance.get_defined_table(table).as_mut().unwrap() };
578                 match module.tables[idx].ref_type.heap_type.top() {
579                     WasmHeapTopType::Extern => {
580                         let gc_ref = VMGcRef::from_raw_u32(raw.get_externref());
581                         let gc_store = store.gc_store_mut()?;
582                         let items = (0..table.size())
583                             .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r)));
584                         table.init_gc_refs(0, items)?;
585                     }
586 
587                     WasmHeapTopType::Any => {
588                         let gc_ref = VMGcRef::from_raw_u32(raw.get_anyref());
589                         let gc_store = store.gc_store_mut()?;
590                         let items = (0..table.size())
591                             .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r)));
592                         table.init_gc_refs(0, items)?;
593                     }
594 
595                     WasmHeapTopType::Func => {
596                         let funcref = NonNull::new(raw.get_funcref().cast::<VMFuncRef>());
597                         let items = (0..table.size()).map(|_| funcref);
598                         table.init_func(0, items)?;
599                     }
600                 }
601             }
602         }
603     }
604 
605     // Note: if the module's table initializer state is in
606     // FuncTable mode, we will lazily initialize tables based on
607     // any statically-precomputed image of FuncIndexes, but there
608     // may still be "leftover segments" that could not be
609     // incorporated. So we have a unified handler here that
610     // iterates over all segments (Segments mode) or leftover
611     // segments (FuncTable mode) to initialize.
612     for segment in module.table_initialization.segments.iter() {
613         let start = unsafe {
614             const_evaluator
615                 .eval(store, context, &segment.offset)
616                 .expect("const expression should be valid")
617         };
618         context.instance.table_init_segment(
619             store,
620             const_evaluator,
621             segment.table_index,
622             &segment.elements,
623             start.get_u64(),
624             0,
625             segment.elements.len(),
626         )?;
627     }
628 
629     Ok(())
630 }
631 
632 fn get_memory_init_start(
633     store: &mut StoreOpaque,
634     init: &MemoryInitializer,
635     instance: &mut Instance,
636 ) -> Result<u64> {
637     let mut context = ConstEvalContext::new(instance);
638     let mut const_evaluator = ConstExprEvaluator::default();
639     unsafe { const_evaluator.eval(store, &mut context, &init.offset) }.map(|v| {
640         match instance.env_module().memories[init.memory_index].idx_type {
641             wasmtime_environ::IndexType::I32 => v.get_u32().into(),
642             wasmtime_environ::IndexType::I64 => v.get_u64(),
643         }
644     })
645 }
646 
647 fn check_memory_init_bounds(
648     store: &mut StoreOpaque,
649     instance: &mut Instance,
650     initializers: &[MemoryInitializer],
651 ) -> Result<()> {
652     for init in initializers {
653         let memory = instance.get_memory(init.memory_index);
654         let start = get_memory_init_start(store, init, instance)?;
655         let end = usize::try_from(start)
656             .ok()
657             .and_then(|start| start.checked_add(init.data.len()));
658 
659         match end {
660             Some(end) if end <= memory.current_length() => {
661                 // Initializer is in bounds
662             }
663             _ => {
664                 bail!("memory out of bounds: data segment does not fit")
665             }
666         }
667     }
668 
669     Ok(())
670 }
671 
672 fn initialize_memories(
673     store: &mut StoreOpaque,
674     context: &mut ConstEvalContext<'_>,
675     const_evaluator: &mut ConstExprEvaluator,
676     module: &Module,
677 ) -> Result<()> {
678     // Delegates to the `init_memory` method which is sort of a duplicate of
679     // `instance.memory_init_segment` but is used at compile-time in other
680     // contexts so is shared here to have only one method of memory
681     // initialization.
682     //
683     // This call to `init_memory` notably implements all the bells and whistles
684     // so errors only happen if an out-of-bounds segment is found, in which case
685     // a trap is returned.
686 
687     struct InitMemoryAtInstantiation<'a, 'b> {
688         module: &'a Module,
689         store: &'a mut StoreOpaque,
690         context: &'a mut ConstEvalContext<'b>,
691         const_evaluator: &'a mut ConstExprEvaluator,
692     }
693 
694     impl InitMemory for InitMemoryAtInstantiation<'_, '_> {
695         fn memory_size_in_bytes(
696             &mut self,
697             memory: wasmtime_environ::MemoryIndex,
698         ) -> Result<u64, SizeOverflow> {
699             let len = self.context.instance.get_memory(memory).current_length();
700             let len = u64::try_from(len).unwrap();
701             Ok(len)
702         }
703 
704         fn eval_offset(
705             &mut self,
706             memory: wasmtime_environ::MemoryIndex,
707             expr: &wasmtime_environ::ConstExpr,
708         ) -> Option<u64> {
709             let val = unsafe { self.const_evaluator.eval(self.store, self.context, expr) }
710                 .expect("const expression should be valid");
711             Some(
712                 match self.context.instance.env_module().memories[memory].idx_type {
713                     wasmtime_environ::IndexType::I32 => val.get_u32().into(),
714                     wasmtime_environ::IndexType::I64 => val.get_u64(),
715                 },
716             )
717         }
718 
719         fn write(
720             &mut self,
721             memory_index: wasmtime_environ::MemoryIndex,
722             init: &wasmtime_environ::StaticMemoryInitializer,
723         ) -> bool {
724             // If this initializer applies to a defined memory but that memory
725             // doesn't need initialization, due to something like copy-on-write
726             // pre-initializing it via mmap magic, then this initializer can be
727             // skipped entirely.
728             if let Some(memory_index) = self.module.defined_memory_index(memory_index) {
729                 if !self.context.instance.memories[memory_index].1.needs_init() {
730                     return true;
731                 }
732             }
733             let memory = self.context.instance.get_memory(memory_index);
734 
735             unsafe {
736                 let src = self.context.instance.wasm_data(init.data.clone());
737                 let offset = usize::try_from(init.offset).unwrap();
738                 let dst = memory.base.as_ptr().add(offset);
739 
740                 assert!(offset + src.len() <= memory.current_length());
741 
742                 // FIXME audit whether this is safe in the presence of shared
743                 // memory
744                 // (https://github.com/bytecodealliance/wasmtime/issues/4203).
745                 ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len())
746             }
747             true
748         }
749     }
750 
751     let ok = module
752         .memory_initialization
753         .init_memory(&mut InitMemoryAtInstantiation {
754             module,
755             store,
756             context,
757             const_evaluator,
758         });
759     if !ok {
760         return Err(Trap::MemoryOutOfBounds.into());
761     }
762 
763     Ok(())
764 }
765 
766 fn check_init_bounds(
767     store: &mut StoreOpaque,
768     instance: &mut Instance,
769     module: &Module,
770 ) -> Result<()> {
771     check_table_init_bounds(store, instance, module)?;
772 
773     match &module.memory_initialization {
774         MemoryInitialization::Segmented(initializers) => {
775             check_memory_init_bounds(store, instance, initializers)?;
776         }
777         // Statically validated already to have everything in-bounds.
778         MemoryInitialization::Static { .. } => {}
779     }
780 
781     Ok(())
782 }
783 
784 fn initialize_globals(
785     store: &mut StoreOpaque,
786     context: &mut ConstEvalContext<'_>,
787     const_evaluator: &mut ConstExprEvaluator,
788     module: &Module,
789 ) -> Result<()> {
790     assert!(core::ptr::eq(&**context.instance.env_module(), module));
791 
792     let mut store = AutoAssertNoGc::new(store);
793 
794     for (index, init) in module.global_initializers.iter() {
795         let raw = unsafe {
796             const_evaluator
797                 .eval(&mut store, context, init)
798                 .expect("should be a valid const expr")
799         };
800 
801         let to = context.instance.global_ptr(index);
802         let wasm_ty = module.globals[module.global_index(index)].wasm_ty;
803 
804         #[cfg(feature = "wmemcheck")]
805         if index.as_u32() == 0 && wasm_ty == wasmtime_environ::WasmValType::I32 {
806             if let Some(wmemcheck) = &mut context.instance.wmemcheck_state {
807                 let size = usize::try_from(raw.get_i32()).unwrap();
808                 wmemcheck.set_stack_size(size);
809             }
810         }
811 
812         // This write is safe because we know we have the correct module for
813         // this instance and its vmctx due to the assert above.
814         unsafe {
815             to.write(VMGlobalDefinition::from_val_raw(&mut store, wasm_ty, raw)?);
816         };
817     }
818     Ok(())
819 }
820 
821 pub(super) fn initialize_instance(
822     store: &mut StoreOpaque,
823     instance: &mut Instance,
824     module: &Module,
825     is_bulk_memory: bool,
826 ) -> Result<()> {
827     // If bulk memory is not enabled, bounds check the data and element segments before
828     // making any changes. With bulk memory enabled, initializers are processed
829     // in-order and side effects are observed up to the point of an out-of-bounds
830     // initializer, so the early checking is not desired.
831     if !is_bulk_memory {
832         check_init_bounds(store, instance, module)?;
833     }
834 
835     let mut context = ConstEvalContext::new(instance);
836     let mut const_evaluator = ConstExprEvaluator::default();
837 
838     initialize_globals(store, &mut context, &mut const_evaluator, module)?;
839     initialize_tables(store, &mut context, &mut const_evaluator, module)?;
840     initialize_memories(store, &mut context, &mut const_evaluator, &module)?;
841 
842     Ok(())
843 }
844 
845 #[cfg(test)]
846 mod tests {
847     use super::*;
848 
849     #[test]
850     fn allocator_traits_are_object_safe() {
851         fn _instance_allocator(_: &dyn InstanceAllocatorImpl) {}
852         fn _instance_allocator_ext(_: &dyn InstanceAllocator) {}
853     }
854 }
855