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