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