1 //! An `Instance` contains all the runtime state used by execution of a 2 //! wasm module (except its callstack and register state). An 3 //! `InstanceHandle` is a reference-counting handle for an `Instance`. 4 5 use crate::prelude::*; 6 use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator}; 7 use crate::runtime::vm::export::Export; 8 use crate::runtime::vm::memory::{Memory, RuntimeMemoryCreator}; 9 use crate::runtime::vm::table::{Table, TableElement, TableElementType}; 10 use crate::runtime::vm::vmcontext::{ 11 VMBuiltinFunctionsArray, VMContext, VMFuncRef, VMFunctionImport, VMGlobalDefinition, 12 VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMOpaqueContext, VMStoreContext, 13 VMTableDefinition, VMTableImport, VMTagDefinition, VMTagImport, 14 }; 15 use crate::runtime::vm::{ 16 ExportFunction, ExportGlobal, ExportGlobalKind, ExportMemory, ExportTable, ExportTag, GcStore, 17 Imports, ModuleRuntimeInfo, SendSyncPtr, VMGcRef, VMStore, VMStoreRawPtr, VmPtr, VmSafe, 18 WasmFault, 19 }; 20 use crate::store::{InstanceId, StoreOpaque}; 21 use alloc::sync::Arc; 22 use core::alloc::Layout; 23 use core::marker; 24 use core::ops::Range; 25 use core::pin::Pin; 26 use core::ptr::NonNull; 27 #[cfg(target_has_atomic = "64")] 28 use core::sync::atomic::AtomicU64; 29 use core::{mem, ptr}; 30 #[cfg(feature = "gc")] 31 use wasmtime_environ::ModuleInternedTypeIndex; 32 use wasmtime_environ::{ 33 DataIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, 34 ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex, HostPtr, MemoryIndex, 35 Module, PrimaryMap, PtrSize, TableIndex, TableInitialValue, TableSegmentElements, TagIndex, 36 Trap, VMCONTEXT_MAGIC, VMOffsets, VMSharedTypeIndex, WasmHeapTopType, 37 packed_option::ReservedValue, 38 }; 39 #[cfg(feature = "wmemcheck")] 40 use wasmtime_wmemcheck::Wmemcheck; 41 42 mod allocator; 43 pub use allocator::*; 44 45 /// The pair of an instance and a raw pointer its associated store. 46 /// 47 /// ### Safety 48 /// 49 /// > **Note**: it's known that the documentation below is documenting an 50 /// > unsound pattern and we're in the process of fixing it, but it'll take 51 /// > some time to refactor. Notably `unpack_mut` is not sound because the 52 /// > returned store pointer can be used to accidentally alias the instance 53 /// > pointer returned as well. 54 /// 55 /// Getting a borrow of a vmctx's store is one of the fundamental bits of unsafe 56 /// code in Wasmtime. No matter how we architect the runtime, some kind of 57 /// unsafe conversion from a raw vmctx pointer that Wasm is using into a Rust 58 /// struct must happen. 59 /// 60 /// It is our responsibility to ensure that multiple (exclusive) borrows of the 61 /// vmctx's store never exist at the same time. The distinction between the 62 /// `Instance` type (which doesn't expose its underlying vmctx pointer or a way 63 /// to get a borrow of its associated store) and this type (which does) is 64 /// designed to help with that. 65 /// 66 /// Going from a `*mut VMContext` to a `&mut StoreInner<T>` is naturally unsafe 67 /// due to the raw pointer usage, but additionally the `T` type parameter needs 68 /// to be the same `T` that was used to define the `dyn VMStore` trait object 69 /// that was stuffed into the vmctx. 70 /// 71 /// ### Usage 72 /// 73 /// Usage generally looks like: 74 /// 75 /// 1. You get a raw `*mut VMContext` from Wasm 76 /// 77 /// 2. You call `InstanceAndStore::from_vmctx` on that raw pointer 78 /// 79 /// 3. You then call `InstanceAndStore::unpack_mut` (or another helper) to get 80 /// the underlying `Pin<&mut Instance>` and `&mut dyn VMStore` (or `&mut 81 /// StoreInner<T>`). 82 /// 83 /// 4. You then use whatever `Instance` methods you need to, each of which take 84 /// a store argument as necessary. 85 /// 86 /// In step (4) you no longer need to worry about double exclusive borrows of 87 /// the store, so long as you don't do (1-2) again. Note also that the borrow 88 /// checker prevents repeating step (3) if you never repeat (1-2). In general, 89 /// steps (1-3) should be done in a single, common, internally-unsafe, 90 /// plumbing-code bottleneck and the raw pointer should never be exposed to Rust 91 /// code that does (4) after the `InstanceAndStore` is created. Follow this 92 /// pattern, and everything using the resulting `Instance` and `Store` can be 93 /// safe code (at least, with regards to accessing the store itself). 94 /// 95 /// As an illustrative example, the common plumbing code for our various 96 /// libcalls performs steps (1-3) before calling into each actual libcall 97 /// implementation function that does (4). The plumbing code hides the raw vmctx 98 /// pointer and never gives out access to it to the libcall implementation 99 /// functions, nor does an `Instance` expose its internal vmctx pointer, which 100 /// would allow unsafely repeating steps (1-2). 101 #[repr(transparent)] 102 pub struct InstanceAndStore { 103 instance: Instance, 104 } 105 106 impl InstanceAndStore { 107 /// Converts the provided `*mut VMContext` to an `InstanceAndStore` 108 /// reference and calls the provided closure with it. 109 /// 110 /// This method will move the `vmctx` pointer backwards to point to the 111 /// original `Instance` that precedes it. The closure is provided a 112 /// temporary reference to the `InstanceAndStore` with a constrained 113 /// lifetime to ensure that it doesn't accidentally escape. 114 /// 115 /// # Safety 116 /// 117 /// Callers must validate that the `vmctx` pointer is a valid allocation and 118 /// that it's valid to acquire `&mut InstanceAndStore` at this time. For 119 /// example this can't be called twice on the same `VMContext` to get two 120 /// active mutable borrows to the same `InstanceAndStore`. 121 /// 122 /// See also the safety discussion in this type's documentation. 123 #[inline] 124 pub(crate) unsafe fn from_vmctx<R>( 125 vmctx: NonNull<VMContext>, 126 f: impl for<'a> FnOnce(&'a mut Self) -> R, 127 ) -> R { 128 const _: () = assert!(mem::size_of::<InstanceAndStore>() == mem::size_of::<Instance>()); 129 let mut ptr = vmctx 130 .byte_sub(mem::size_of::<Instance>()) 131 .cast::<InstanceAndStore>(); 132 133 f(ptr.as_mut()) 134 } 135 136 /// Unpacks this `InstanceAndStore` into its underlying `Instance` and `dyn 137 /// VMStore`. 138 #[inline] 139 pub(crate) fn unpack_mut(&mut self) -> (Pin<&mut Instance>, &mut dyn VMStore) { 140 unsafe { 141 let store = &mut *self.store_ptr(); 142 (Pin::new_unchecked(&mut self.instance), store) 143 } 144 } 145 146 /// Gets a pointer to this instance's `Store` which was originally 147 /// configured on creation. 148 /// 149 /// # Panics 150 /// 151 /// May panic if the originally configured store was `None`. That can happen 152 /// for host functions so host functions can't be queried what their 153 /// original `Store` was since it's just retained as null (since host 154 /// functions are shared amongst threads and don't all share the same 155 /// store). 156 #[inline] 157 fn store_ptr(&self) -> *mut dyn VMStore { 158 self.instance.store.unwrap().0.as_ptr() 159 } 160 } 161 162 /// A type that roughly corresponds to a WebAssembly instance, but is also used 163 /// for host-defined objects. 164 /// 165 /// Instances here can correspond to actual instantiated modules, but it's also 166 /// used ubiquitously for host-defined objects. For example creating a 167 /// host-defined memory will have a `module` that looks like it exports a single 168 /// memory (and similar for other constructs). 169 /// 170 /// This `Instance` type is used as a ubiquitous representation for WebAssembly 171 /// values, whether or not they were created on the host or through a module. 172 /// 173 /// # Ownership 174 /// 175 /// This structure is never allocated directly but is instead managed through 176 /// an `InstanceHandle`. This structure ends with a `VMContext` which has a 177 /// dynamic size corresponding to the `module` configured within. Memory 178 /// management of this structure is always done through `InstanceHandle` as the 179 /// sole owner of an instance. 180 /// 181 /// # `Instance` and `Pin` 182 /// 183 /// Given an instance it is accompanied with trailing memory for the 184 /// appropriate `VMContext`. The `Instance` also holds `runtime_info` and other 185 /// information pointing to relevant offsets for the `VMContext`. Thus it is 186 /// not sound to mutate `runtime_info` after an instance is created. More 187 /// generally it's also not safe to "swap" instances, for example given two 188 /// `&mut Instance` values it's not sound to swap them as then the `VMContext` 189 /// values are inaccurately described. 190 /// 191 /// To encapsulate this guarantee this type is only ever mutated through Rust's 192 /// `Pin` type. All mutable methods here take `self: Pin<&mut Self>` which 193 /// statically disallows safe access to `&mut Instance`. There are assorted 194 /// "projection methods" to go from `Pin<&mut Instance>` to `&mut T` for 195 /// individual fields, for example `memories_mut`. More methods can be added as 196 /// necessary or methods may also be added to project multiple fields at a time 197 /// if necessary to. The precise ergonomics around getting mutable access to 198 /// some fields (but notably not `runtime_info`) is probably going to evolve 199 /// over time. 200 /// 201 /// Note that is is not sound to basically ever pass around `&mut Instance`. 202 /// That should always instead be `Pin<&mut Instance>`. All usage of 203 /// `Pin::new_unchecked` should be here in this module in just a few `unsafe` 204 /// locations and it's recommended to use existing helpers if you can. 205 #[repr(C)] // ensure that the vmctx field is last. 206 pub struct Instance { 207 /// The index, within a `Store` that this instance lives at 208 id: InstanceId, 209 210 /// The runtime info (corresponding to the "compiled module" 211 /// abstraction in higher layers) that is retained and needed for 212 /// lazy initialization. This provides access to the underlying 213 /// Wasm module entities, the compiled JIT code, metadata about 214 /// functions, lazy initialization state, etc. 215 runtime_info: ModuleRuntimeInfo, 216 217 /// WebAssembly linear memory data. 218 /// 219 /// This is where all runtime information about defined linear memories in 220 /// this module lives. 221 /// 222 /// The `MemoryAllocationIndex` was given from our `InstanceAllocator` and 223 /// must be given back to the instance allocator when deallocating each 224 /// memory. 225 memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 226 227 /// WebAssembly table data. 228 /// 229 /// Like memories, this is only for defined tables in the module and 230 /// contains all of their runtime state. 231 /// 232 /// The `TableAllocationIndex` was given from our `InstanceAllocator` and 233 /// must be given back to the instance allocator when deallocating each 234 /// table. 235 tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 236 237 /// Stores the dropped passive element segments in this instantiation by index. 238 /// If the index is present in the set, the segment has been dropped. 239 dropped_elements: EntitySet<ElemIndex>, 240 241 /// Stores the dropped passive data segments in this instantiation by index. 242 /// If the index is present in the set, the segment has been dropped. 243 dropped_data: EntitySet<DataIndex>, 244 245 // TODO: add support for multiple memories; `wmemcheck_state` corresponds to 246 // memory 0. 247 #[cfg(feature = "wmemcheck")] 248 pub(crate) wmemcheck_state: Option<Wmemcheck>, 249 250 /// Self-pointer back to `Store<T>` and its functions. Not present for 251 /// the brief time that `Store<T>` is itself being created. Also not 252 /// present for some niche uses that are disconnected from stores (e.g. 253 /// cross-thread stuff used in `InstancePre`) 254 store: Option<VMStoreRawPtr>, 255 256 /// Additional context used by compiled wasm code. This field is last, and 257 /// represents a dynamically-sized array that extends beyond the nominal 258 /// end of the struct (similar to a flexible array member). 259 vmctx: OwnedVMContext<VMContext>, 260 } 261 262 impl Instance { 263 /// Create an instance at the given memory address. 264 /// 265 /// It is assumed the memory was properly aligned and the 266 /// allocation was `alloc_size` in bytes. 267 fn new( 268 req: InstanceAllocationRequest, 269 memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 270 tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 271 memory_tys: &PrimaryMap<MemoryIndex, wasmtime_environ::Memory>, 272 ) -> InstanceHandle { 273 let module = req.runtime_info.env_module(); 274 let dropped_elements = EntitySet::with_capacity(module.passive_elements.len()); 275 let dropped_data = EntitySet::with_capacity(module.passive_data_map.len()); 276 277 #[cfg(not(feature = "wmemcheck"))] 278 let _ = memory_tys; 279 280 let mut ret = OwnedInstance::new(Instance { 281 id: req.id, 282 runtime_info: req.runtime_info.clone(), 283 memories, 284 tables, 285 dropped_elements, 286 dropped_data, 287 #[cfg(feature = "wmemcheck")] 288 wmemcheck_state: { 289 if req.wmemcheck { 290 let size = memory_tys 291 .iter() 292 .next() 293 .map(|memory| memory.1.limits.min) 294 .unwrap_or(0) 295 * 64 296 * 1024; 297 Some(Wmemcheck::new(size as usize)) 298 } else { 299 None 300 } 301 }, 302 store: None, 303 vmctx: OwnedVMContext::new(), 304 }); 305 306 // SAFETY: this vmctx was allocated with the same layout above, so it 307 // should be safe to initialize with the same values here. 308 unsafe { 309 ret.get_mut().initialize_vmctx( 310 module, 311 req.runtime_info.offsets(), 312 req.store, 313 req.imports, 314 ); 315 } 316 ret 317 } 318 319 /// Converts the provided `*mut VMContext` to an `Instance` pointer and runs 320 /// the provided closure with the instance. 321 /// 322 /// This method will move the `vmctx` pointer backwards to point to the 323 /// original `Instance` that precedes it. The closure is provided a 324 /// temporary version of the `Instance` pointer with a constrained lifetime 325 /// to the closure to ensure it doesn't accidentally escape. 326 /// 327 /// # Unsafety 328 /// 329 /// Callers must validate that the `vmctx` pointer is a valid allocation 330 /// and that it's valid to acquire `Pin<&mut Instance>` at this time. For example 331 /// this can't be called twice on the same `VMContext` to get two active 332 /// pointers to the same `Instance`. 333 #[inline] 334 pub unsafe fn from_vmctx<R>( 335 vmctx: NonNull<VMContext>, 336 f: impl FnOnce(Pin<&mut Instance>) -> R, 337 ) -> R { 338 let mut ptr = vmctx 339 .byte_sub(mem::size_of::<Instance>()) 340 .cast::<Instance>(); 341 f(Pin::new_unchecked(ptr.as_mut())) 342 } 343 344 pub(crate) fn env_module(&self) -> &Arc<wasmtime_environ::Module> { 345 self.runtime_info.env_module() 346 } 347 348 #[cfg(feature = "gc")] 349 pub(crate) fn runtime_module(&self) -> Option<&crate::Module> { 350 match &self.runtime_info { 351 ModuleRuntimeInfo::Module(m) => Some(m), 352 ModuleRuntimeInfo::Bare(_) => None, 353 } 354 } 355 356 /// Translate a module-level interned type index into an engine-level 357 /// interned type index. 358 #[cfg(feature = "gc")] 359 pub fn engine_type_index(&self, module_index: ModuleInternedTypeIndex) -> VMSharedTypeIndex { 360 self.runtime_info.engine_type_index(module_index) 361 } 362 363 #[inline] 364 fn offsets(&self) -> &VMOffsets<HostPtr> { 365 self.runtime_info.offsets() 366 } 367 368 /// Return the indexed `VMFunctionImport`. 369 fn imported_function(&self, index: FuncIndex) -> &VMFunctionImport { 370 unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmfunction_import(index)) } 371 } 372 373 /// Return the index `VMTableImport`. 374 fn imported_table(&self, index: TableIndex) -> &VMTableImport { 375 unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmtable_import(index)) } 376 } 377 378 /// Return the indexed `VMMemoryImport`. 379 fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport { 380 unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmmemory_import(index)) } 381 } 382 383 /// Return the indexed `VMGlobalImport`. 384 fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport { 385 unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmglobal_import(index)) } 386 } 387 388 /// Return the indexed `VMTagImport`. 389 fn imported_tag(&self, index: TagIndex) -> &VMTagImport { 390 unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmtag_import(index)) } 391 } 392 393 /// Return the indexed `VMTagDefinition`. 394 pub fn tag_ptr(&self, index: DefinedTagIndex) -> NonNull<VMTagDefinition> { 395 unsafe { self.vmctx_plus_offset_raw(self.offsets().vmctx_vmtag_definition(index)) } 396 } 397 398 /// Return the indexed `VMTableDefinition`. 399 pub fn table(&self, index: DefinedTableIndex) -> VMTableDefinition { 400 unsafe { self.table_ptr(index).read() } 401 } 402 403 /// Updates the value for a defined table to `VMTableDefinition`. 404 fn set_table(self: Pin<&mut Self>, index: DefinedTableIndex, table: VMTableDefinition) { 405 unsafe { 406 self.table_ptr(index).write(table); 407 } 408 } 409 410 /// Return a pointer to the `index`'th table within this instance, stored 411 /// in vmctx memory. 412 pub fn table_ptr(&self, index: DefinedTableIndex) -> NonNull<VMTableDefinition> { 413 unsafe { self.vmctx_plus_offset_raw(self.offsets().vmctx_vmtable_definition(index)) } 414 } 415 416 /// Get a locally defined or imported memory. 417 pub(crate) fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition { 418 if let Some(defined_index) = self.env_module().defined_memory_index(index) { 419 self.memory(defined_index) 420 } else { 421 let import = self.imported_memory(index); 422 unsafe { VMMemoryDefinition::load(import.from.as_ptr()) } 423 } 424 } 425 426 /// Get a locally defined or imported memory. 427 #[cfg(feature = "threads")] 428 pub(crate) fn get_runtime_memory(self: Pin<&mut Self>, index: MemoryIndex) -> &mut Memory { 429 if let Some(defined_index) = self.env_module().defined_memory_index(index) { 430 unsafe { &mut *self.get_defined_memory(defined_index) } 431 } else { 432 let import = self.imported_memory(index); 433 unsafe { 434 let ptr = Instance::from_vmctx(import.vmctx.as_non_null(), |i| { 435 i.get_defined_memory(import.index) 436 }); 437 &mut *ptr 438 } 439 } 440 } 441 442 /// Return the indexed `VMMemoryDefinition`, loaded from vmctx memory 443 /// already. 444 pub fn memory(&self, index: DefinedMemoryIndex) -> VMMemoryDefinition { 445 unsafe { VMMemoryDefinition::load(self.memory_ptr(index).as_ptr()) } 446 } 447 448 /// Set the indexed memory to `VMMemoryDefinition`. 449 fn set_memory(&self, index: DefinedMemoryIndex, mem: VMMemoryDefinition) { 450 unsafe { 451 self.memory_ptr(index).write(mem); 452 } 453 } 454 455 /// Return the address of the specified memory at `index` within this vmctx. 456 /// 457 /// Note that the returned pointer resides in wasm-code-readable-memory in 458 /// the vmctx. 459 pub fn memory_ptr(&self, index: DefinedMemoryIndex) -> NonNull<VMMemoryDefinition> { 460 unsafe { 461 self.vmctx_plus_offset::<VmPtr<_>>(self.offsets().vmctx_vmmemory_pointer(index)) 462 .as_non_null() 463 } 464 } 465 466 /// Return the indexed `VMGlobalDefinition`. 467 pub fn global_ptr(&self, index: DefinedGlobalIndex) -> NonNull<VMGlobalDefinition> { 468 unsafe { self.vmctx_plus_offset_raw(self.offsets().vmctx_vmglobal_definition(index)) } 469 } 470 471 /// Get a raw pointer to the global at the given index regardless whether it 472 /// is defined locally or imported from another module. 473 /// 474 /// Panics if the index is out of bound or is the reserved value. 475 pub(crate) fn defined_or_imported_global_ptr( 476 self: Pin<&mut Self>, 477 index: GlobalIndex, 478 ) -> NonNull<VMGlobalDefinition> { 479 if let Some(index) = self.env_module().defined_global_index(index) { 480 self.global_ptr(index) 481 } else { 482 self.imported_global(index).from.as_non_null() 483 } 484 } 485 486 /// Get all globals within this instance. 487 /// 488 /// Returns both import and defined globals. 489 /// 490 /// Returns both exported and non-exported globals. 491 /// 492 /// Gives access to the full globals space. 493 pub fn all_globals(&self) -> impl ExactSizeIterator<Item = (GlobalIndex, ExportGlobal)> + '_ { 494 let module = self.env_module().clone(); 495 module 496 .globals 497 .keys() 498 .map(move |idx| (idx, self.get_exported_global(idx))) 499 } 500 501 /// Get the globals defined in this instance (not imported). 502 pub fn defined_globals( 503 &self, 504 ) -> impl ExactSizeIterator<Item = (DefinedGlobalIndex, ExportGlobal)> + '_ { 505 let module = self.env_module().clone(); 506 module 507 .globals 508 .keys() 509 .skip(module.num_imported_globals) 510 .map(move |global_idx| { 511 let def_idx = module.defined_global_index(global_idx).unwrap(); 512 let global = ExportGlobal { 513 definition: self.global_ptr(def_idx), 514 kind: ExportGlobalKind::Instance(self.vmctx(), def_idx), 515 global: self.env_module().globals[global_idx], 516 }; 517 (def_idx, global) 518 }) 519 } 520 521 /// Return a pointer to the interrupts structure 522 #[inline] 523 pub fn vm_store_context(&self) -> NonNull<Option<VmPtr<VMStoreContext>>> { 524 unsafe { self.vmctx_plus_offset_raw(self.offsets().ptr.vmctx_store_context()) } 525 } 526 527 /// Return a pointer to the global epoch counter used by this instance. 528 #[cfg(target_has_atomic = "64")] 529 pub fn epoch_ptr(self: Pin<&mut Self>) -> &mut Option<VmPtr<AtomicU64>> { 530 let offset = self.offsets().ptr.vmctx_epoch_ptr(); 531 unsafe { self.vmctx_plus_offset_mut(offset) } 532 } 533 534 /// Return a pointer to the collector-specific heap data. 535 pub fn gc_heap_data(self: Pin<&mut Self>) -> &mut Option<VmPtr<u8>> { 536 let offset = self.offsets().ptr.vmctx_gc_heap_data(); 537 unsafe { self.vmctx_plus_offset_mut(offset) } 538 } 539 540 pub(crate) unsafe fn set_store(mut self: Pin<&mut Self>, store: Option<NonNull<dyn VMStore>>) { 541 *self.as_mut().store_mut() = store.map(VMStoreRawPtr); 542 if let Some(mut store) = store { 543 let store = store.as_mut(); 544 self.vm_store_context() 545 .write(Some(store.vm_store_context_ptr().into())); 546 #[cfg(target_has_atomic = "64")] 547 { 548 *self.as_mut().epoch_ptr() = 549 Some(NonNull::from(store.engine().epoch_counter()).into()); 550 } 551 552 if self.env_module().needs_gc_heap { 553 self.as_mut().set_gc_heap(Some(store.gc_store().expect( 554 "if we need a GC heap, then `Instance::new_raw` should have already \ 555 allocated it for us", 556 ))); 557 } else { 558 self.as_mut().set_gc_heap(None); 559 } 560 } else { 561 self.vm_store_context().write(None); 562 #[cfg(target_has_atomic = "64")] 563 { 564 *self.as_mut().epoch_ptr() = None; 565 } 566 self.as_mut().set_gc_heap(None); 567 } 568 } 569 570 unsafe fn set_gc_heap(self: Pin<&mut Self>, gc_store: Option<&GcStore>) { 571 if let Some(gc_store) = gc_store { 572 *self.gc_heap_data() = Some(gc_store.gc_heap.vmctx_gc_heap_data().into()); 573 } else { 574 *self.gc_heap_data() = None; 575 } 576 } 577 578 /// Return a reference to the vmctx used by compiled wasm code. 579 #[inline] 580 pub fn vmctx(&self) -> NonNull<VMContext> { 581 InstanceLayout::vmctx(self) 582 } 583 584 /// Lookup a function by index. 585 /// 586 /// # Panics 587 /// 588 /// Panics if `index` is out of bounds for this instance. 589 pub fn get_exported_func(&self, index: FuncIndex) -> ExportFunction { 590 let func_ref = self.get_func_ref(index).unwrap(); 591 ExportFunction { func_ref } 592 } 593 594 /// Lookup a table by index. 595 /// 596 /// # Panics 597 /// 598 /// Panics if `index` is out of bounds for this instance. 599 pub fn get_exported_table(&self, index: TableIndex) -> ExportTable { 600 let ty = self.env_module().tables[index]; 601 let (definition, vmctx, index) = 602 if let Some(def_index) = self.env_module().defined_table_index(index) { 603 (self.table_ptr(def_index), self.vmctx(), def_index) 604 } else { 605 let import = self.imported_table(index); 606 ( 607 import.from.as_non_null(), 608 import.vmctx.as_non_null(), 609 import.index, 610 ) 611 }; 612 ExportTable { 613 definition, 614 vmctx, 615 table: ty, 616 index, 617 } 618 } 619 620 /// Lookup a memory by index. 621 /// 622 /// # Panics 623 /// 624 /// Panics if `index` is out-of-bounds for this instance. 625 pub fn get_exported_memory(&self, index: MemoryIndex) -> ExportMemory { 626 let (definition, vmctx, def_index) = 627 if let Some(def_index) = self.env_module().defined_memory_index(index) { 628 (self.memory_ptr(def_index), self.vmctx(), def_index) 629 } else { 630 let import = self.imported_memory(index); 631 ( 632 import.from.as_non_null(), 633 import.vmctx.as_non_null(), 634 import.index, 635 ) 636 }; 637 ExportMemory { 638 definition, 639 vmctx, 640 memory: self.env_module().memories[index], 641 index: def_index, 642 } 643 } 644 645 fn get_exported_global(&self, index: GlobalIndex) -> ExportGlobal { 646 let global = self.env_module().globals[index]; 647 if let Some(def_index) = self.env_module().defined_global_index(index) { 648 ExportGlobal { 649 definition: self.global_ptr(def_index), 650 kind: ExportGlobalKind::Instance(self.vmctx(), def_index), 651 global, 652 } 653 } else { 654 ExportGlobal::from_vmimport(self.imported_global(index), global) 655 } 656 } 657 658 fn get_exported_tag(&self, index: TagIndex) -> ExportTag { 659 let tag = self.env_module().tags[index]; 660 let (vmctx, definition, index) = 661 if let Some(def_index) = self.env_module().defined_tag_index(index) { 662 (self.vmctx(), self.tag_ptr(def_index), def_index) 663 } else { 664 let import = self.imported_tag(index); 665 ( 666 import.vmctx.as_non_null(), 667 import.from.as_non_null(), 668 import.index, 669 ) 670 }; 671 ExportTag { 672 definition, 673 vmctx, 674 index, 675 tag, 676 } 677 } 678 679 /// Return an iterator over the exports of this instance. 680 /// 681 /// Specifically, it provides access to the key-value pairs, where the keys 682 /// are export names, and the values are export declarations which can be 683 /// resolved `lookup_by_declaration`. 684 pub fn exports(&self) -> wasmparser::collections::index_map::Iter<'_, String, EntityIndex> { 685 self.env_module().exports.iter() 686 } 687 688 /// Return the table index for the given `VMTableDefinition`. 689 pub unsafe fn table_index(&self, table: &VMTableDefinition) -> DefinedTableIndex { 690 let index = DefinedTableIndex::new( 691 usize::try_from( 692 (table as *const VMTableDefinition) 693 .offset_from(self.table_ptr(DefinedTableIndex::new(0)).as_ptr()), 694 ) 695 .unwrap(), 696 ); 697 assert!(index.index() < self.tables.len()); 698 index 699 } 700 701 /// Get the given memory's page size, in bytes. 702 pub(crate) fn memory_page_size(&self, index: MemoryIndex) -> usize { 703 usize::try_from(self.env_module().memories[index].page_size()).unwrap() 704 } 705 706 /// Grow memory by the specified amount of pages. 707 /// 708 /// Returns `None` if memory can't be grown by the specified amount 709 /// of pages. Returns `Some` with the old size in bytes if growth was 710 /// successful. 711 pub(crate) fn memory_grow( 712 self: Pin<&mut Self>, 713 store: &mut dyn VMStore, 714 index: MemoryIndex, 715 delta: u64, 716 ) -> Result<Option<usize>, Error> { 717 match self.env_module().defined_memory_index(index) { 718 Some(idx) => self.defined_memory_grow(store, idx, delta), 719 None => { 720 let import = self.imported_memory(index); 721 unsafe { 722 Instance::from_vmctx(import.vmctx.as_non_null(), |i| { 723 i.defined_memory_grow(store, import.index, delta) 724 }) 725 } 726 } 727 } 728 } 729 730 fn defined_memory_grow( 731 mut self: Pin<&mut Self>, 732 store: &mut dyn VMStore, 733 idx: DefinedMemoryIndex, 734 delta: u64, 735 ) -> Result<Option<usize>, Error> { 736 let memory = &mut self.as_mut().memories_mut()[idx].1; 737 738 let result = unsafe { memory.grow(delta, Some(store)) }; 739 740 // Update the state used by a non-shared Wasm memory in case the base 741 // pointer and/or the length changed. 742 if memory.as_shared_memory().is_none() { 743 let vmmemory = memory.vmmemory(); 744 self.set_memory(idx, vmmemory); 745 } 746 747 result 748 } 749 750 pub(crate) fn table_element_type( 751 self: Pin<&mut Self>, 752 table_index: TableIndex, 753 ) -> TableElementType { 754 unsafe { (*self.get_table(table_index)).element_type() } 755 } 756 757 /// Grow table by the specified amount of elements, filling them with 758 /// `init_value`. 759 /// 760 /// Returns `None` if table can't be grown by the specified amount of 761 /// elements, or if `init_value` is the wrong type of table element. 762 pub(crate) fn table_grow( 763 self: Pin<&mut Self>, 764 store: &mut dyn VMStore, 765 table_index: TableIndex, 766 delta: u64, 767 init_value: TableElement, 768 ) -> Result<Option<usize>, Error> { 769 self.with_defined_table_index_and_instance(table_index, |i, instance| { 770 instance.defined_table_grow(store, i, delta, init_value) 771 }) 772 } 773 774 fn defined_table_grow( 775 mut self: Pin<&mut Self>, 776 store: &mut dyn VMStore, 777 table_index: DefinedTableIndex, 778 delta: u64, 779 init_value: TableElement, 780 ) -> Result<Option<usize>, Error> { 781 let table = &mut self 782 .as_mut() 783 .tables_mut() 784 .get_mut(table_index) 785 .unwrap_or_else(|| panic!("no table for index {}", table_index.index())) 786 .1; 787 788 let result = unsafe { table.grow(delta, init_value, store) }; 789 790 // Keep the `VMContext` pointers used by compiled Wasm code up to 791 // date. 792 let element = table.vmtable(); 793 self.set_table(table_index, element); 794 795 result 796 } 797 798 fn alloc_layout(offsets: &VMOffsets<HostPtr>) -> Layout { 799 let size = mem::size_of::<Self>() 800 .checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap()) 801 .unwrap(); 802 let align = mem::align_of::<Self>(); 803 Layout::from_size_align(size, align).unwrap() 804 } 805 806 fn type_ids_array(&self) -> NonNull<VmPtr<VMSharedTypeIndex>> { 807 unsafe { self.vmctx_plus_offset_raw(self.offsets().ptr.vmctx_type_ids_array()) } 808 } 809 810 /// Construct a new VMFuncRef for the given function 811 /// (imported or defined in this module) and store into the given 812 /// location. Used during lazy initialization. 813 /// 814 /// Note that our current lazy-init scheme actually calls this every 815 /// time the funcref pointer is fetched; this turns out to be better 816 /// than tracking state related to whether it's been initialized 817 /// before, because resetting that state on (re)instantiation is 818 /// very expensive if there are many funcrefs. 819 fn construct_func_ref( 820 &self, 821 index: FuncIndex, 822 type_index: VMSharedTypeIndex, 823 into: *mut VMFuncRef, 824 ) { 825 let func_ref = if let Some(def_index) = self.env_module().defined_func_index(index) { 826 VMFuncRef { 827 array_call: self 828 .runtime_info 829 .array_to_wasm_trampoline(def_index) 830 .expect("should have array-to-Wasm trampoline for escaping function") 831 .into(), 832 wasm_call: Some(self.runtime_info.function(def_index).into()), 833 vmctx: VMOpaqueContext::from_vmcontext(self.vmctx()).into(), 834 type_index, 835 } 836 } else { 837 let import = self.imported_function(index); 838 VMFuncRef { 839 array_call: import.array_call, 840 wasm_call: Some(import.wasm_call), 841 vmctx: import.vmctx, 842 type_index, 843 } 844 }; 845 846 // Safety: we have a `&mut self`, so we have exclusive access 847 // to this Instance. 848 unsafe { 849 ptr::write(into, func_ref); 850 } 851 } 852 853 /// Get a `&VMFuncRef` for the given `FuncIndex`. 854 /// 855 /// Returns `None` if the index is the reserved index value. 856 /// 857 /// The returned reference is a stable reference that won't be moved and can 858 /// be passed into JIT code. 859 pub(crate) fn get_func_ref(&self, index: FuncIndex) -> Option<NonNull<VMFuncRef>> { 860 if index == FuncIndex::reserved_value() { 861 return None; 862 } 863 864 // Safety: we have a `&mut self`, so we have exclusive access 865 // to this Instance. 866 unsafe { 867 // For now, we eagerly initialize an funcref struct in-place 868 // whenever asked for a reference to it. This is mostly 869 // fine, because in practice each funcref is unlikely to be 870 // requested more than a few times: once-ish for funcref 871 // tables used for call_indirect (the usual compilation 872 // strategy places each function in the table at most once), 873 // and once or a few times when fetching exports via API. 874 // Note that for any case driven by table accesses, the lazy 875 // table init behaves like a higher-level cache layer that 876 // protects this initialization from happening multiple 877 // times, via that particular table at least. 878 // 879 // When `ref.func` becomes more commonly used or if we 880 // otherwise see a use-case where this becomes a hotpath, 881 // we can reconsider by using some state to track 882 // "uninitialized" explicitly, for example by zeroing the 883 // funcrefs (perhaps together with other 884 // zeroed-at-instantiate-time state) or using a separate 885 // is-initialized bitmap. 886 // 887 // We arrived at this design because zeroing memory is 888 // expensive, so it's better for instantiation performance 889 // if we don't have to track "is-initialized" state at 890 // all! 891 let func = &self.env_module().functions[index]; 892 let sig = func.signature.unwrap_engine_type_index(); 893 let func_ref = self 894 .vmctx_plus_offset_raw::<VMFuncRef>(self.offsets().vmctx_func_ref(func.func_ref)); 895 self.construct_func_ref(index, sig, func_ref.as_ptr()); 896 897 Some(func_ref) 898 } 899 } 900 901 /// Get the passive elements segment at the given index. 902 /// 903 /// Returns an empty segment if the index is out of bounds or if the segment 904 /// has been dropped. 905 /// 906 /// The `storage` parameter should always be `None`; it is a bit of a hack 907 /// to work around lifetime issues. 908 pub(crate) fn passive_element_segment<'a>( 909 &self, 910 storage: &'a mut Option<(Arc<wasmtime_environ::Module>, TableSegmentElements)>, 911 elem_index: ElemIndex, 912 ) -> &'a TableSegmentElements { 913 debug_assert!(storage.is_none()); 914 *storage = Some(( 915 // TODO: this `clone()` shouldn't be necessary but is used for now to 916 // inform `rustc` that the lifetime of the elements here are 917 // disconnected from the lifetime of `self`. 918 self.env_module().clone(), 919 // NB: fall back to an expressions-based list of elements which 920 // doesn't have static type information (as opposed to 921 // `TableSegmentElements::Functions`) since we don't know what type 922 // is needed in the caller's context. Let the type be inferred by 923 // how they use the segment. 924 TableSegmentElements::Expressions(Box::new([])), 925 )); 926 let (module, empty) = storage.as_ref().unwrap(); 927 928 match module.passive_elements_map.get(&elem_index) { 929 Some(index) if !self.dropped_elements.contains(elem_index) => { 930 &module.passive_elements[*index] 931 } 932 _ => empty, 933 } 934 } 935 936 /// The `table.init` operation: initializes a portion of a table with a 937 /// passive element. 938 /// 939 /// # Errors 940 /// 941 /// Returns a `Trap` error when the range within the table is out of bounds 942 /// or the range within the passive element is out of bounds. 943 pub(crate) fn table_init( 944 self: Pin<&mut Self>, 945 store: &mut StoreOpaque, 946 table_index: TableIndex, 947 elem_index: ElemIndex, 948 dst: u64, 949 src: u64, 950 len: u64, 951 ) -> Result<(), Trap> { 952 let mut storage = None; 953 let elements = self.passive_element_segment(&mut storage, elem_index); 954 let mut const_evaluator = ConstExprEvaluator::default(); 955 Self::table_init_segment( 956 store, 957 self.id, 958 &mut const_evaluator, 959 table_index, 960 elements, 961 dst, 962 src, 963 len, 964 ) 965 } 966 967 pub(crate) fn table_init_segment( 968 store: &mut StoreOpaque, 969 id: InstanceId, 970 const_evaluator: &mut ConstExprEvaluator, 971 table_index: TableIndex, 972 elements: &TableSegmentElements, 973 dst: u64, 974 src: u64, 975 len: u64, 976 ) -> Result<(), Trap> { 977 // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init 978 979 let mut instance = store.instance_mut(id); 980 let table = unsafe { &mut *instance.as_mut().get_table(table_index) }; 981 let src = usize::try_from(src).map_err(|_| Trap::TableOutOfBounds)?; 982 let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds)?; 983 let module = instance.env_module().clone(); 984 985 match elements { 986 TableSegmentElements::Functions(funcs) => { 987 let elements = funcs 988 .get(src..) 989 .and_then(|s| s.get(..len)) 990 .ok_or(Trap::TableOutOfBounds)?; 991 table.init_func(dst, elements.iter().map(|idx| instance.get_func_ref(*idx)))?; 992 } 993 TableSegmentElements::Expressions(exprs) => { 994 let exprs = exprs 995 .get(src..) 996 .and_then(|s| s.get(..len)) 997 .ok_or(Trap::TableOutOfBounds)?; 998 let top = module.tables[table_index].ref_type.heap_type.top(); 999 let mut context = ConstEvalContext::new(id); 1000 match top { 1001 WasmHeapTopType::Extern => table.init_gc_refs( 1002 dst, 1003 exprs.iter().map(|expr| unsafe { 1004 let raw = const_evaluator 1005 .eval(store, &mut context, expr) 1006 .expect("const expr should be valid"); 1007 VMGcRef::from_raw_u32(raw.get_externref()) 1008 }), 1009 )?, 1010 WasmHeapTopType::Any => table.init_gc_refs( 1011 dst, 1012 exprs.iter().map(|expr| unsafe { 1013 let raw = const_evaluator 1014 .eval(store, &mut context, expr) 1015 .expect("const expr should be valid"); 1016 VMGcRef::from_raw_u32(raw.get_anyref()) 1017 }), 1018 )?, 1019 WasmHeapTopType::Func => table.init_func( 1020 dst, 1021 exprs.iter().map(|expr| unsafe { 1022 NonNull::new( 1023 const_evaluator 1024 .eval(store, &mut context, expr) 1025 .expect("const expr should be valid") 1026 .get_funcref() 1027 .cast(), 1028 ) 1029 }), 1030 )?, 1031 WasmHeapTopType::Cont => todo!(), // FIXME: #10248 stack switching support. 1032 } 1033 } 1034 } 1035 1036 Ok(()) 1037 } 1038 1039 /// Drop an element. 1040 pub(crate) fn elem_drop(self: Pin<&mut Self>, elem_index: ElemIndex) { 1041 // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop 1042 1043 self.dropped_elements_mut().insert(elem_index); 1044 1045 // Note that we don't check that we actually removed a segment because 1046 // dropping a non-passive segment is a no-op (not a trap). 1047 } 1048 1049 /// Get a locally-defined memory. 1050 pub fn get_defined_memory(self: Pin<&mut Self>, index: DefinedMemoryIndex) -> *mut Memory { 1051 // SAFETY: the `unsafe` here is projecting from `*mut (A, B)` to 1052 // `*mut A`, which should be a safe operation to do. 1053 unsafe { &raw mut (*self.memories_mut().get_raw_mut(index).unwrap()).1 } 1054 } 1055 1056 /// Do a `memory.copy` 1057 /// 1058 /// # Errors 1059 /// 1060 /// Returns a `Trap` error when the source or destination ranges are out of 1061 /// bounds. 1062 pub(crate) fn memory_copy( 1063 self: Pin<&mut Self>, 1064 dst_index: MemoryIndex, 1065 dst: u64, 1066 src_index: MemoryIndex, 1067 src: u64, 1068 len: u64, 1069 ) -> Result<(), Trap> { 1070 // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy 1071 1072 let src_mem = self.get_memory(src_index); 1073 let dst_mem = self.get_memory(dst_index); 1074 1075 let src = self.validate_inbounds(src_mem.current_length(), src, len)?; 1076 let dst = self.validate_inbounds(dst_mem.current_length(), dst, len)?; 1077 let len = usize::try_from(len).unwrap(); 1078 1079 // Bounds and casts are checked above, by this point we know that 1080 // everything is safe. 1081 unsafe { 1082 let dst = dst_mem.base.as_ptr().add(dst); 1083 let src = src_mem.base.as_ptr().add(src); 1084 // FIXME audit whether this is safe in the presence of shared memory 1085 // (https://github.com/bytecodealliance/wasmtime/issues/4203). 1086 ptr::copy(src, dst, len); 1087 } 1088 1089 Ok(()) 1090 } 1091 1092 fn validate_inbounds(&self, max: usize, ptr: u64, len: u64) -> Result<usize, Trap> { 1093 let oob = || Trap::MemoryOutOfBounds; 1094 let end = ptr 1095 .checked_add(len) 1096 .and_then(|i| usize::try_from(i).ok()) 1097 .ok_or_else(oob)?; 1098 if end > max { 1099 Err(oob()) 1100 } else { 1101 Ok(ptr.try_into().unwrap()) 1102 } 1103 } 1104 1105 /// Perform the `memory.fill` operation on a locally defined memory. 1106 /// 1107 /// # Errors 1108 /// 1109 /// Returns a `Trap` error if the memory range is out of bounds. 1110 pub(crate) fn memory_fill( 1111 self: Pin<&mut Self>, 1112 memory_index: MemoryIndex, 1113 dst: u64, 1114 val: u8, 1115 len: u64, 1116 ) -> Result<(), Trap> { 1117 let memory = self.get_memory(memory_index); 1118 let dst = self.validate_inbounds(memory.current_length(), dst, len)?; 1119 let len = usize::try_from(len).unwrap(); 1120 1121 // Bounds and casts are checked above, by this point we know that 1122 // everything is safe. 1123 unsafe { 1124 let dst = memory.base.as_ptr().add(dst); 1125 // FIXME audit whether this is safe in the presence of shared memory 1126 // (https://github.com/bytecodealliance/wasmtime/issues/4203). 1127 ptr::write_bytes(dst, val, len); 1128 } 1129 1130 Ok(()) 1131 } 1132 1133 /// Get the internal storage range of a particular Wasm data segment. 1134 pub(crate) fn wasm_data_range(&self, index: DataIndex) -> Range<u32> { 1135 match self.env_module().passive_data_map.get(&index) { 1136 Some(range) if !self.dropped_data.contains(index) => range.clone(), 1137 _ => 0..0, 1138 } 1139 } 1140 1141 /// Given an internal storage range of a Wasm data segment (or subset of a 1142 /// Wasm data segment), get the data's raw bytes. 1143 pub(crate) fn wasm_data(&self, range: Range<u32>) -> &[u8] { 1144 let start = usize::try_from(range.start).unwrap(); 1145 let end = usize::try_from(range.end).unwrap(); 1146 &self.runtime_info.wasm_data()[start..end] 1147 } 1148 1149 /// Performs the `memory.init` operation. 1150 /// 1151 /// # Errors 1152 /// 1153 /// Returns a `Trap` error if the destination range is out of this module's 1154 /// memory's bounds or if the source range is outside the data segment's 1155 /// bounds. 1156 pub(crate) fn memory_init( 1157 self: Pin<&mut Self>, 1158 memory_index: MemoryIndex, 1159 data_index: DataIndex, 1160 dst: u64, 1161 src: u32, 1162 len: u32, 1163 ) -> Result<(), Trap> { 1164 let range = self.wasm_data_range(data_index); 1165 self.memory_init_segment(memory_index, range, dst, src, len) 1166 } 1167 1168 pub(crate) fn memory_init_segment( 1169 self: Pin<&mut Self>, 1170 memory_index: MemoryIndex, 1171 range: Range<u32>, 1172 dst: u64, 1173 src: u32, 1174 len: u32, 1175 ) -> Result<(), Trap> { 1176 // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init 1177 1178 let memory = self.get_memory(memory_index); 1179 let data = self.wasm_data(range); 1180 let dst = self.validate_inbounds(memory.current_length(), dst, len.into())?; 1181 let src = self.validate_inbounds(data.len(), src.into(), len.into())?; 1182 let len = len as usize; 1183 1184 unsafe { 1185 let src_start = data.as_ptr().add(src); 1186 let dst_start = memory.base.as_ptr().add(dst); 1187 // FIXME audit whether this is safe in the presence of shared memory 1188 // (https://github.com/bytecodealliance/wasmtime/issues/4203). 1189 ptr::copy_nonoverlapping(src_start, dst_start, len); 1190 } 1191 1192 Ok(()) 1193 } 1194 1195 /// Drop the given data segment, truncating its length to zero. 1196 pub(crate) fn data_drop(self: Pin<&mut Self>, data_index: DataIndex) { 1197 self.dropped_data_mut().insert(data_index); 1198 1199 // Note that we don't check that we actually removed a segment because 1200 // dropping a non-passive segment is a no-op (not a trap). 1201 } 1202 1203 /// Get a table by index regardless of whether it is locally-defined 1204 /// or an imported, foreign table. Ensure that the given range of 1205 /// elements in the table is lazily initialized. We define this 1206 /// operation all-in-one for safety, to ensure the lazy-init 1207 /// happens. 1208 /// 1209 /// Takes an `Iterator` for the index-range to lazy-initialize, 1210 /// for flexibility. This can be a range, single item, or empty 1211 /// sequence, for example. The iterator should return indices in 1212 /// increasing order, so that the break-at-out-of-bounds behavior 1213 /// works correctly. 1214 pub(crate) fn get_table_with_lazy_init( 1215 self: Pin<&mut Self>, 1216 table_index: TableIndex, 1217 range: impl Iterator<Item = u64>, 1218 ) -> *mut Table { 1219 self.with_defined_table_index_and_instance(table_index, |idx, instance| { 1220 instance.get_defined_table_with_lazy_init(idx, range) 1221 }) 1222 } 1223 1224 /// Gets the raw runtime table data structure owned by this instance 1225 /// given the provided `idx`. 1226 /// 1227 /// The `range` specified is eagerly initialized for funcref tables. 1228 pub fn get_defined_table_with_lazy_init( 1229 mut self: Pin<&mut Self>, 1230 idx: DefinedTableIndex, 1231 range: impl Iterator<Item = u64>, 1232 ) -> *mut Table { 1233 let elt_ty = self.tables[idx].1.element_type(); 1234 1235 if elt_ty == TableElementType::Func { 1236 for i in range { 1237 let value = match self.tables[idx].1.get(None, i) { 1238 Some(value) => value, 1239 None => { 1240 // Out-of-bounds; caller will handle by likely 1241 // throwing a trap. No work to do to lazy-init 1242 // beyond the end. 1243 break; 1244 } 1245 }; 1246 1247 if !value.is_uninit() { 1248 continue; 1249 } 1250 1251 // The table element `i` is uninitialized and is now being 1252 // initialized. This must imply that a `precompiled` list of 1253 // function indices is available for this table. The precompiled 1254 // list is extracted and then it is consulted with `i` to 1255 // determine the function that is going to be initialized. Note 1256 // that `i` may be outside the limits of the static 1257 // initialization so it's a fallible `get` instead of an index. 1258 let module = self.env_module(); 1259 let precomputed = match &module.table_initialization.initial_values[idx] { 1260 TableInitialValue::Null { precomputed } => precomputed, 1261 TableInitialValue::Expr(_) => unreachable!(), 1262 }; 1263 // Panicking here helps catch bugs rather than silently truncating by accident. 1264 let func_index = precomputed.get(usize::try_from(i).unwrap()).cloned(); 1265 let func_ref = func_index.and_then(|func_index| self.get_func_ref(func_index)); 1266 self.as_mut().tables_mut()[idx] 1267 .1 1268 .set(i, TableElement::FuncRef(func_ref)) 1269 .expect("Table type should match and index should be in-bounds"); 1270 } 1271 } 1272 1273 // SAFETY: the `unsafe` here is projecting from `*mut (A, B)` to 1274 // `*mut A`, which should be a safe operation to do. 1275 unsafe { &raw mut (*self.tables_mut().get_raw_mut(idx).unwrap()).1 } 1276 } 1277 1278 /// Get a table by index regardless of whether it is locally-defined or an 1279 /// imported, foreign table. 1280 pub(crate) fn get_table(self: Pin<&mut Self>, table_index: TableIndex) -> *mut Table { 1281 self.with_defined_table_index_and_instance(table_index, |idx, instance| unsafe { 1282 // SAFETY: the `unsafe` here is projecting from `*mut (A, B)` to 1283 // `*mut A`, which should be a safe operation to do. 1284 &raw mut (*instance.tables_mut().get_raw_mut(idx).unwrap()).1 1285 }) 1286 } 1287 1288 /// Get a locally-defined table. 1289 pub(crate) fn get_defined_table(self: Pin<&mut Self>, index: DefinedTableIndex) -> *mut Table { 1290 // SAFETY: the `unsafe` here is projecting from `*mut (A, B)` to 1291 // `*mut A`, which should be a safe operation to do. 1292 unsafe { &raw mut (*self.tables_mut().get_raw_mut(index).unwrap()).1 } 1293 } 1294 1295 pub(crate) fn with_defined_table_index_and_instance<R>( 1296 self: Pin<&mut Self>, 1297 index: TableIndex, 1298 f: impl FnOnce(DefinedTableIndex, Pin<&mut Instance>) -> R, 1299 ) -> R { 1300 if let Some(defined_table_index) = self.env_module().defined_table_index(index) { 1301 f(defined_table_index, self) 1302 } else { 1303 let import = self.imported_table(index); 1304 unsafe { 1305 Instance::from_vmctx(import.vmctx.as_non_null(), |foreign_instance| { 1306 let foreign_table_def = import.from.as_ptr(); 1307 let foreign_table_index = foreign_instance.table_index(&*foreign_table_def); 1308 f(foreign_table_index, foreign_instance) 1309 }) 1310 } 1311 } 1312 } 1313 1314 /// Initialize the VMContext data associated with this Instance. 1315 /// 1316 /// The `VMContext` memory is assumed to be uninitialized; any field 1317 /// that we need in a certain state will be explicitly written by this 1318 /// function. 1319 unsafe fn initialize_vmctx( 1320 mut self: Pin<&mut Self>, 1321 module: &Module, 1322 offsets: &VMOffsets<HostPtr>, 1323 store: StorePtr, 1324 imports: Imports, 1325 ) { 1326 assert!(ptr::eq(module, self.env_module().as_ref())); 1327 1328 self.vmctx_plus_offset_raw::<u32>(offsets.ptr.vmctx_magic()) 1329 .write(VMCONTEXT_MAGIC); 1330 self.as_mut().set_store(store.as_raw()); 1331 1332 // Initialize shared types 1333 let types = NonNull::from(self.runtime_info.type_ids()); 1334 self.type_ids_array().write(types.cast().into()); 1335 1336 // Initialize the built-in functions 1337 static BUILTINS: VMBuiltinFunctionsArray = VMBuiltinFunctionsArray::INIT; 1338 let ptr = BUILTINS.expose_provenance(); 1339 self.vmctx_plus_offset_raw(offsets.ptr.vmctx_builtin_functions()) 1340 .write(VmPtr::from(ptr)); 1341 1342 // Initialize the imports 1343 debug_assert_eq!(imports.functions.len(), module.num_imported_funcs); 1344 ptr::copy_nonoverlapping( 1345 imports.functions.as_ptr(), 1346 self.vmctx_plus_offset_raw(offsets.vmctx_imported_functions_begin()) 1347 .as_ptr(), 1348 imports.functions.len(), 1349 ); 1350 debug_assert_eq!(imports.tables.len(), module.num_imported_tables); 1351 ptr::copy_nonoverlapping( 1352 imports.tables.as_ptr(), 1353 self.vmctx_plus_offset_raw(offsets.vmctx_imported_tables_begin()) 1354 .as_ptr(), 1355 imports.tables.len(), 1356 ); 1357 debug_assert_eq!(imports.memories.len(), module.num_imported_memories); 1358 ptr::copy_nonoverlapping( 1359 imports.memories.as_ptr(), 1360 self.vmctx_plus_offset_raw(offsets.vmctx_imported_memories_begin()) 1361 .as_ptr(), 1362 imports.memories.len(), 1363 ); 1364 debug_assert_eq!(imports.globals.len(), module.num_imported_globals); 1365 ptr::copy_nonoverlapping( 1366 imports.globals.as_ptr(), 1367 self.vmctx_plus_offset_raw(offsets.vmctx_imported_globals_begin()) 1368 .as_ptr(), 1369 imports.globals.len(), 1370 ); 1371 1372 debug_assert_eq!(imports.tags.len(), module.num_imported_tags); 1373 ptr::copy_nonoverlapping( 1374 imports.tags.as_ptr(), 1375 self.vmctx_plus_offset_raw(offsets.vmctx_imported_tags_begin()) 1376 .as_ptr(), 1377 imports.tags.len(), 1378 ); 1379 1380 // N.B.: there is no need to initialize the funcrefs array because we 1381 // eagerly construct each element in it whenever asked for a reference 1382 // to that element. In other words, there is no state needed to track 1383 // the lazy-init, so we don't need to initialize any state now. 1384 1385 // Initialize the defined tables 1386 let mut ptr = self.vmctx_plus_offset_raw(offsets.vmctx_tables_begin()); 1387 let tables = self.as_mut().tables_mut(); 1388 for i in 0..module.num_defined_tables() { 1389 ptr.write(tables[DefinedTableIndex::new(i)].1.vmtable()); 1390 ptr = ptr.add(1); 1391 } 1392 1393 // Initialize the defined memories. This fills in both the 1394 // `defined_memories` table and the `owned_memories` table at the same 1395 // time. Entries in `defined_memories` hold a pointer to a definition 1396 // (all memories) whereas the `owned_memories` hold the actual 1397 // definitions of memories owned (not shared) in the module. 1398 let mut ptr = self.vmctx_plus_offset_raw(offsets.vmctx_memories_begin()); 1399 let mut owned_ptr = self.vmctx_plus_offset_raw(offsets.vmctx_owned_memories_begin()); 1400 let memories = self.as_mut().memories_mut(); 1401 for i in 0..module.num_defined_memories() { 1402 let defined_memory_index = DefinedMemoryIndex::new(i); 1403 let memory_index = module.memory_index(defined_memory_index); 1404 if module.memories[memory_index].shared { 1405 let def_ptr = memories[defined_memory_index] 1406 .1 1407 .as_shared_memory() 1408 .unwrap() 1409 .vmmemory_ptr(); 1410 ptr.write(VmPtr::from(def_ptr)); 1411 } else { 1412 owned_ptr.write(memories[defined_memory_index].1.vmmemory()); 1413 ptr.write(VmPtr::from(owned_ptr)); 1414 owned_ptr = owned_ptr.add(1); 1415 } 1416 ptr = ptr.add(1); 1417 } 1418 1419 // Zero-initialize the globals so that nothing is uninitialized memory 1420 // after this function returns. The globals are actually initialized 1421 // with their const expression initializers after the instance is fully 1422 // allocated. 1423 for (index, _init) in module.global_initializers.iter() { 1424 self.global_ptr(index).write(VMGlobalDefinition::new()); 1425 } 1426 1427 // Initialize the defined tags 1428 let mut ptr = self.vmctx_plus_offset_raw(offsets.vmctx_tags_begin()); 1429 for i in 0..module.num_defined_tags() { 1430 let defined_index = DefinedTagIndex::new(i); 1431 let tag_index = module.tag_index(defined_index); 1432 let tag = module.tags[tag_index]; 1433 ptr.write(VMTagDefinition::new( 1434 tag.signature.unwrap_engine_type_index(), 1435 )); 1436 ptr = ptr.add(1); 1437 } 1438 } 1439 1440 /// Attempts to convert from the host `addr` specified to a WebAssembly 1441 /// based address recorded in `WasmFault`. 1442 /// 1443 /// This method will check all linear memories that this instance contains 1444 /// to see if any of them contain `addr`. If one does then `Some` is 1445 /// returned with metadata about the wasm fault. Otherwise `None` is 1446 /// returned and `addr` doesn't belong to this instance. 1447 pub fn wasm_fault(&self, addr: usize) -> Option<WasmFault> { 1448 let mut fault = None; 1449 for (_, (_, memory)) in self.memories.iter() { 1450 let accessible = memory.wasm_accessible(); 1451 if accessible.start <= addr && addr < accessible.end { 1452 // All linear memories should be disjoint so assert that no 1453 // prior fault has been found. 1454 assert!(fault.is_none()); 1455 fault = Some(WasmFault { 1456 memory_size: memory.byte_size(), 1457 wasm_address: u64::try_from(addr - accessible.start).unwrap(), 1458 }); 1459 } 1460 } 1461 fault 1462 } 1463 1464 /// Returns the id, within this instance's store, that it's assigned. 1465 pub fn id(&self) -> InstanceId { 1466 self.id 1467 } 1468 1469 /// Get all memories within this instance. 1470 /// 1471 /// Returns both import and defined memories. 1472 /// 1473 /// Returns both exported and non-exported memories. 1474 /// 1475 /// Gives access to the full memories space. 1476 pub fn all_memories<'a>( 1477 &'a self, 1478 ) -> impl ExactSizeIterator<Item = (MemoryIndex, ExportMemory)> + 'a { 1479 let indices = (0..self.env_module().memories.len()) 1480 .map(|i| MemoryIndex::new(i)) 1481 .collect::<Vec<_>>(); 1482 indices 1483 .into_iter() 1484 .map(|i| (i, self.get_exported_memory(i))) 1485 } 1486 1487 /// Return the memories defined in this instance (not imported). 1488 pub fn defined_memories<'a>(&'a self) -> impl ExactSizeIterator<Item = ExportMemory> + 'a { 1489 let num_imported = self.env_module().num_imported_memories; 1490 self.all_memories() 1491 .skip(num_imported) 1492 .map(|(_i, memory)| memory) 1493 } 1494 1495 /// Lookup an item with the given index. 1496 /// 1497 /// # Panics 1498 /// 1499 /// Panics if `export` is not valid for this instance. 1500 pub fn get_export_by_index(&self, export: EntityIndex) -> Export { 1501 match export { 1502 EntityIndex::Function(i) => Export::Function(self.get_exported_func(i)), 1503 EntityIndex::Global(i) => Export::Global(self.get_exported_global(i)), 1504 EntityIndex::Table(i) => Export::Table(self.get_exported_table(i)), 1505 EntityIndex::Memory(i) => Export::Memory(self.get_exported_memory(i)), 1506 EntityIndex::Tag(i) => Export::Tag(self.get_exported_tag(i)), 1507 } 1508 } 1509 1510 fn store_mut(self: Pin<&mut Self>) -> &mut Option<VMStoreRawPtr> { 1511 // SAFETY: this is a pin-projection to get a mutable reference to an 1512 // internal field and is safe so long as the `&mut Self` temporarily 1513 // created is not overwritten, which it isn't here. 1514 unsafe { &mut self.get_unchecked_mut().store } 1515 } 1516 1517 fn dropped_elements_mut(self: Pin<&mut Self>) -> &mut EntitySet<ElemIndex> { 1518 // SAFETY: see `store_mut` above. 1519 unsafe { &mut self.get_unchecked_mut().dropped_elements } 1520 } 1521 1522 fn dropped_data_mut(self: Pin<&mut Self>) -> &mut EntitySet<DataIndex> { 1523 // SAFETY: see `store_mut` above. 1524 unsafe { &mut self.get_unchecked_mut().dropped_data } 1525 } 1526 1527 fn memories_mut( 1528 self: Pin<&mut Self>, 1529 ) -> &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)> { 1530 // SAFETY: see `store_mut` above. 1531 unsafe { &mut self.get_unchecked_mut().memories } 1532 } 1533 1534 fn tables_mut( 1535 self: Pin<&mut Self>, 1536 ) -> &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)> { 1537 // SAFETY: see `store_mut` above. 1538 unsafe { &mut self.get_unchecked_mut().tables } 1539 } 1540 1541 #[cfg(feature = "wmemcheck")] 1542 pub(super) fn wmemcheck_state_mut(self: Pin<&mut Self>) -> &mut Option<Wmemcheck> { 1543 // SAFETY: see `store_mut` above. 1544 unsafe { &mut self.get_unchecked_mut().wmemcheck_state } 1545 } 1546 } 1547 1548 // SAFETY: `layout` should describe this accurately and `OwnedVMContext` is the 1549 // last field of `ComponentInstance`. 1550 unsafe impl InstanceLayout for Instance { 1551 const INIT_ZEROED: bool = false; 1552 type VMContext = VMContext; 1553 1554 fn layout(&self) -> Layout { 1555 Self::alloc_layout(self.runtime_info.offsets()) 1556 } 1557 1558 fn owned_vmctx(&self) -> &OwnedVMContext<VMContext> { 1559 &self.vmctx 1560 } 1561 1562 fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<VMContext> { 1563 &mut self.vmctx 1564 } 1565 } 1566 1567 pub type InstanceHandle = OwnedInstance<Instance>; 1568 1569 /// A handle holding an `Instance` of a WebAssembly module. 1570 /// 1571 /// This structure is an owning handle of the `instance` contained internally. 1572 /// When this value goes out of scope it will deallocate the `Instance` and all 1573 /// memory associated with it. 1574 /// 1575 /// Note that this lives within a `StoreOpaque` on a list of instances that a 1576 /// store is keeping alive. 1577 #[derive(Debug)] 1578 #[repr(transparent)] // guarantee this is a zero-cost wrapper 1579 pub struct OwnedInstance<T: InstanceLayout> { 1580 /// The raw pointer to the instance that was allocated. 1581 /// 1582 /// Note that this is not equivalent to `Box<Instance>` because the 1583 /// allocation here has a `VMContext` trailing after it. Thus the custom 1584 /// destructor to invoke the `dealloc` function with the appropriate 1585 /// layout. 1586 instance: SendSyncPtr<T>, 1587 _marker: marker::PhantomData<Box<(T, OwnedVMContext<T::VMContext>)>>, 1588 } 1589 1590 /// Structure that must be placed at the end of a type implementing 1591 /// `InstanceLayout`. 1592 #[repr(align(16))] // match the alignment of VMContext 1593 pub struct OwnedVMContext<T> { 1594 /// A pointer to the `vmctx` field at the end of the `structure`. 1595 /// 1596 /// If you're looking at this a reasonable question would be "why do we need 1597 /// a pointer to ourselves?" because after all the pointer's value is 1598 /// trivially derivable from any `&Instance` pointer. The rationale for this 1599 /// field's existence is subtle, but it's required for correctness. The 1600 /// short version is "this makes miri happy". 1601 /// 1602 /// The long version of why this field exists is that the rules that MIRI 1603 /// uses to ensure pointers are used correctly have various conditions on 1604 /// them depend on how pointers are used. More specifically if `*mut T` is 1605 /// derived from `&mut T`, then that invalidates all prior pointers drived 1606 /// from the `&mut T`. This means that while we liberally want to re-acquire 1607 /// a `*mut VMContext` throughout the implementation of `Instance` the 1608 /// trivial way, a function `fn vmctx(Pin<&mut Instance>) -> *mut VMContext` 1609 /// would effectively invalidate all prior `*mut VMContext` pointers 1610 /// acquired. The purpose of this field is to serve as a sort of 1611 /// source-of-truth for where `*mut VMContext` pointers come from. 1612 /// 1613 /// This field is initialized when the `Instance` is created with the 1614 /// original allocation's pointer. That means that the provenance of this 1615 /// pointer contains the entire allocation (both instance and `VMContext`). 1616 /// This provenance bit is then "carried through" where `fn vmctx` will base 1617 /// all returned pointers on this pointer itself. This provides the means of 1618 /// never invalidating this pointer throughout MIRI and additionally being 1619 /// able to still temporarily have `Pin<&mut Instance>` methods and such. 1620 /// 1621 /// It's important to note, though, that this is not here purely for MIRI. 1622 /// The careful construction of the `fn vmctx` method has ramifications on 1623 /// the LLVM IR generated, for example. A historical CVE on Wasmtime, 1624 /// GHSA-ch89-5g45-qwc7, was caused due to relying on undefined behavior. By 1625 /// deriving VMContext pointers from this pointer it specifically hints to 1626 /// LLVM that trickery is afoot and it properly informs `noalias` and such 1627 /// annotations and analysis. More-or-less this pointer is actually loaded 1628 /// in LLVM IR which helps defeat otherwise present aliasing optimizations, 1629 /// which we want, since writes to this should basically never be optimized 1630 /// out. 1631 /// 1632 /// As a final note it's worth pointing out that the machine code generated 1633 /// for accessing `fn vmctx` is still as one would expect. This member isn't 1634 /// actually ever loaded at runtime (or at least shouldn't be). Perhaps in 1635 /// the future if the memory consumption of this field is a problem we could 1636 /// shrink it slightly, but for now one extra pointer per wasm instance 1637 /// seems not too bad. 1638 vmctx_self_reference: SendSyncPtr<T>, 1639 1640 /// This field ensures that going from `Pin<&mut T>` to `&mut T` is not a 1641 /// safe operation. 1642 _marker: core::marker::PhantomPinned, 1643 } 1644 1645 impl<T> OwnedVMContext<T> { 1646 /// Creates a new blank vmctx to place at the end of an instance. 1647 pub fn new() -> OwnedVMContext<T> { 1648 OwnedVMContext { 1649 vmctx_self_reference: SendSyncPtr::new(NonNull::dangling()), 1650 _marker: core::marker::PhantomPinned, 1651 } 1652 } 1653 } 1654 1655 /// Helper trait to plumb both core instances and component instances into 1656 /// `OwnedInstance` below. 1657 /// 1658 /// # Safety 1659 /// 1660 /// This trait requires `layout` to correctly describe `Self` and appropriately 1661 /// allocate space for `Self::VMContext` afterwards. Additionally the field 1662 /// returned by `owned_vmctx()` must be the last field in the structure. 1663 pub unsafe trait InstanceLayout { 1664 /// Whether or not to allocate this instance with `alloc_zeroed` or `alloc`. 1665 const INIT_ZEROED: bool; 1666 1667 /// The trailing `VMContext` type at the end of this instance. 1668 type VMContext; 1669 1670 /// The memory layout to use to allocate and deallocate this instance. 1671 fn layout(&self) -> Layout; 1672 1673 fn owned_vmctx(&self) -> &OwnedVMContext<Self::VMContext>; 1674 fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<Self::VMContext>; 1675 1676 /// Returns the `vmctx_self_reference` set above. 1677 #[inline] 1678 fn vmctx(&self) -> NonNull<Self::VMContext> { 1679 // The definition of this method is subtle but intentional. The goal 1680 // here is that effectively this should return `&mut self.vmctx`, but 1681 // it's not quite so simple. Some more documentation is available on the 1682 // `vmctx_self_reference` field, but the general idea is that we're 1683 // creating a pointer to return with proper provenance. Provenance is 1684 // still in the works in Rust at the time of this writing but the load 1685 // of the `self.vmctx_self_reference` field is important here as it 1686 // affects how LLVM thinks about aliasing with respect to the returned 1687 // pointer. 1688 // 1689 // The intention of this method is to codegen to machine code as `&mut 1690 // self.vmctx`, however. While it doesn't show up like this in LLVM IR 1691 // (there's an actual load of the field) it does look like that by the 1692 // time the backend runs. (that's magic to me, the backend removing 1693 // loads...) 1694 let owned_vmctx = self.owned_vmctx(); 1695 let owned_vmctx_raw = NonNull::from(owned_vmctx); 1696 // SAFETY: it's part of the contract of `InstanceLayout` and the usage 1697 // with `OwnedInstance` that this indeed points to the vmctx. 1698 let addr = unsafe { owned_vmctx_raw.add(1) }; 1699 owned_vmctx 1700 .vmctx_self_reference 1701 .as_non_null() 1702 .with_addr(addr.addr()) 1703 } 1704 1705 /// Helper function to access various locations offset from our `*mut 1706 /// VMContext` object. 1707 /// 1708 /// Note that this method takes `&self` as an argument but returns 1709 /// `NonNull<T>` which is frequently used to mutate said memory. This is an 1710 /// intentional design decision where the safety of the modification of 1711 /// memory is placed as a burden onto the caller. The implementation of this 1712 /// method explicitly does not require `&mut self` to acquire mutable 1713 /// provenance to update the `VMContext` region. Instead all pointers into 1714 /// the `VMContext` area have provenance/permissions to write. 1715 /// 1716 /// Also note though that care must be taken to ensure that reads/writes of 1717 /// memory must only happen where appropriate, for example a non-atomic 1718 /// write (as most are) should never happen concurrently with another read 1719 /// or write. It's generally on the burden of the caller to adhere to this. 1720 /// 1721 /// Also of note is that most of the time the usage of this method falls 1722 /// into one of: 1723 /// 1724 /// * Something in the VMContext is being read or written. In that case use 1725 /// `vmctx_plus_offset` or `vmctx_plus_offset_mut` if possible due to 1726 /// that having a safer lifetime. 1727 /// 1728 /// * A pointer is being created to pass to other VM* data structures. In 1729 /// that situation the lifetime of all VM data structures are typically 1730 /// tied to the `Store<T>` which is what provides the guarantees around 1731 /// concurrency/etc. 1732 /// 1733 /// There's quite a lot of unsafety riding on this method, especially 1734 /// related to the ascription `T` of the byte `offset`. It's hoped that in 1735 /// the future we're able to settle on an in theory safer design. 1736 /// 1737 /// # Safety 1738 /// 1739 /// This method is unsafe because the `offset` must be within bounds of the 1740 /// `VMContext` object trailing this instance. Additionally `T` must be a 1741 /// valid ascription of the value that resides at that location. 1742 unsafe fn vmctx_plus_offset_raw<T: VmSafe>(&self, offset: impl Into<u32>) -> NonNull<T> { 1743 // SAFETY: the safety requirements of `byte_add` are forwarded to this 1744 // method's caller. 1745 unsafe { 1746 self.vmctx() 1747 .byte_add(usize::try_from(offset.into()).unwrap()) 1748 .cast() 1749 } 1750 } 1751 1752 /// Helper above `vmctx_plus_offset_raw` which transfers the lifetime of 1753 /// `&self` to the returned reference `&T`. 1754 /// 1755 /// # Safety 1756 /// 1757 /// See the safety documentation of `vmctx_plus_offset_raw`. 1758 unsafe fn vmctx_plus_offset<T: VmSafe>(&self, offset: impl Into<u32>) -> &T { 1759 // SAFETY: this method has the same safety requirements as 1760 // `vmctx_plus_offset_raw`. 1761 unsafe { self.vmctx_plus_offset_raw(offset).as_ref() } 1762 } 1763 1764 /// Helper above `vmctx_plus_offset_raw` which transfers the lifetime of 1765 /// `&mut self` to the returned reference `&mut T`. 1766 /// 1767 /// # Safety 1768 /// 1769 /// See the safety documentation of `vmctx_plus_offset_raw`. 1770 unsafe fn vmctx_plus_offset_mut<T: VmSafe>( 1771 self: Pin<&mut Self>, 1772 offset: impl Into<u32>, 1773 ) -> &mut T { 1774 // SAFETY: this method has the same safety requirements as 1775 // `vmctx_plus_offset_raw`. 1776 unsafe { self.vmctx_plus_offset_raw(offset).as_mut() } 1777 } 1778 } 1779 1780 impl<T: InstanceLayout> OwnedInstance<T> { 1781 /// Allocates a new `OwnedInstance` and places `instance` inside of it. 1782 /// 1783 /// This will `instance` 1784 pub(super) fn new(mut instance: T) -> OwnedInstance<T> { 1785 let layout = instance.layout(); 1786 debug_assert!(layout.size() >= size_of_val(&instance)); 1787 debug_assert!(layout.align() >= align_of_val(&instance)); 1788 1789 // SAFETY: it's up to us to assert that `layout` has a non-zero size, 1790 // which is asserted here. 1791 let ptr = unsafe { 1792 assert!(layout.size() > 0); 1793 if T::INIT_ZEROED { 1794 alloc::alloc::alloc_zeroed(layout) 1795 } else { 1796 alloc::alloc::alloc(layout) 1797 } 1798 }; 1799 if ptr.is_null() { 1800 alloc::alloc::handle_alloc_error(layout); 1801 } 1802 let instance_ptr = NonNull::new(ptr.cast::<T>()).unwrap(); 1803 1804 // SAFETY: it's part of the unsafe contract of `InstanceLayout` that the 1805 // `add` here is appropriate for the layout allocated. 1806 let vmctx_self_reference = unsafe { instance_ptr.add(1).cast() }; 1807 instance.owned_vmctx_mut().vmctx_self_reference = vmctx_self_reference.into(); 1808 1809 // SAFETY: we allocated above and it's an unsafe contract of 1810 // `InstanceLayout` that the layout is suitable for writing the 1811 // instance. 1812 unsafe { 1813 instance_ptr.write(instance); 1814 } 1815 1816 let ret = OwnedInstance { 1817 instance: SendSyncPtr::new(instance_ptr), 1818 _marker: marker::PhantomData, 1819 }; 1820 1821 // Double-check various vmctx calculations are correct. 1822 debug_assert_eq!( 1823 vmctx_self_reference.addr(), 1824 // SAFETY: `InstanceLayout` should guarantee it's safe to add 1 to 1825 // the last field to get a pointer to 1-byte-past-the-end of an 1826 // object, which should be valid. 1827 unsafe { NonNull::from(ret.get().owned_vmctx()).add(1).addr() } 1828 ); 1829 debug_assert_eq!(vmctx_self_reference.addr(), ret.get().vmctx().addr()); 1830 1831 ret 1832 } 1833 1834 /// Gets the raw underlying `&Instance` from this handle. 1835 pub fn get(&self) -> &T { 1836 // SAFETY: this is an owned instance handle that retains exclusive 1837 // ownership of the `Instance` inside. With `&self` given we know 1838 // this pointer is valid valid and the returned lifetime is connected 1839 // to `self` so that should also be valid. 1840 unsafe { self.instance.as_non_null().as_ref() } 1841 } 1842 1843 /// Same as [`Self::get`] except for mutability. 1844 pub fn get_mut(&mut self) -> Pin<&mut T> { 1845 // SAFETY: The lifetime concerns here are the same as `get` above. 1846 // Otherwise `new_unchecked` is used here to uphold the contract that 1847 // instances are always pinned in memory. 1848 unsafe { Pin::new_unchecked(self.instance.as_non_null().as_mut()) } 1849 } 1850 } 1851 1852 impl<T: InstanceLayout> Drop for OwnedInstance<T> { 1853 fn drop(&mut self) { 1854 unsafe { 1855 let layout = self.get().layout(); 1856 ptr::drop_in_place(self.instance.as_ptr()); 1857 alloc::alloc::dealloc(self.instance.as_ptr().cast(), layout); 1858 } 1859 } 1860 } 1861