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