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