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