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