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