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