1 use crate::Trap; 2 use crate::prelude::*; 3 use crate::store::{StoreInstanceId, StoreOpaque}; 4 use crate::trampoline::generate_memory_export; 5 use crate::{AsContext, AsContextMut, Engine, MemoryType, StoreContext, StoreContextMut}; 6 use core::cell::UnsafeCell; 7 use core::fmt; 8 use core::slice; 9 use core::time::Duration; 10 use wasmtime_environ::DefinedMemoryIndex; 11 12 pub use crate::runtime::vm::WaitResult; 13 14 /// Error for out of bounds [`Memory`] access. 15 #[derive(Debug)] 16 #[non_exhaustive] 17 pub struct MemoryAccessError { 18 // Keep struct internals private for future extensibility. 19 _private: (), 20 } 21 22 impl fmt::Display for MemoryAccessError { 23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 24 write!(f, "out of bounds memory access") 25 } 26 } 27 28 impl core::error::Error for MemoryAccessError {} 29 30 /// A WebAssembly linear memory. 31 /// 32 /// WebAssembly memories represent a contiguous array of bytes that have a size 33 /// that is always a multiple of the WebAssembly page size, currently 64 34 /// kilobytes. 35 /// 36 /// WebAssembly memory is used for global data (not to be confused with wasm 37 /// `global` items), statics in C/C++/Rust, shadow stack memory, etc. Accessing 38 /// wasm memory is generally quite fast. 39 /// 40 /// Memories, like other wasm items, are owned by a [`Store`](crate::Store). 41 /// 42 /// # `Memory` and Safety 43 /// 44 /// Linear memory is a lynchpin of safety for WebAssembly. In Wasmtime there are 45 /// safe methods of interacting with a [`Memory`]: 46 /// 47 /// * [`Memory::read`] 48 /// * [`Memory::write`] 49 /// * [`Memory::data`] 50 /// * [`Memory::data_mut`] 51 /// 52 /// Note that all of these consider the entire store context as borrowed for the 53 /// duration of the call or the duration of the returned slice. This largely 54 /// means that while the function is running you'll be unable to borrow anything 55 /// else from the store. This includes getting access to the `T` on 56 /// [`Store<T>`](crate::Store), but it also means that you can't recursively 57 /// call into WebAssembly for instance. 58 /// 59 /// If you'd like to dip your toes into handling [`Memory`] in a more raw 60 /// fashion (e.g. by using raw pointers or raw slices), then there's a few 61 /// important points to consider when doing so: 62 /// 63 /// * Any recursive calls into WebAssembly can possibly modify any byte of the 64 /// entire memory. This means that whenever wasm is called Rust can't have any 65 /// long-lived borrows live across the wasm function call. Slices like `&mut 66 /// [u8]` will be violated because they're not actually exclusive at that 67 /// point, and slices like `&[u8]` are also violated because their contents 68 /// may be mutated. 69 /// 70 /// * WebAssembly memories can grow, and growth may change the base pointer. 71 /// This means that even holding a raw pointer to memory over a wasm function 72 /// call is also incorrect. Anywhere in the function call the base address of 73 /// memory may change. Note that growth can also be requested from the 74 /// embedding API as well. 75 /// 76 /// As a general rule of thumb it's recommended to stick to the safe methods of 77 /// [`Memory`] if you can. It's not advised to use raw pointers or `unsafe` 78 /// operations because of how easy it is to accidentally get things wrong. 79 /// 80 /// Some examples of safely interacting with memory are: 81 /// 82 /// ```rust 83 /// use wasmtime::{Memory, Store, MemoryAccessError}; 84 /// 85 /// // Memory can be read and written safely with the `Memory::read` and 86 /// // `Memory::write` methods. 87 /// // An error is returned if the copy did not succeed. 88 /// fn safe_examples(mem: Memory, store: &mut Store<()>) -> Result<(), MemoryAccessError> { 89 /// let offset = 5; 90 /// mem.write(&mut *store, offset, b"hello")?; 91 /// let mut buffer = [0u8; 5]; 92 /// mem.read(&store, offset, &mut buffer)?; 93 /// assert_eq!(b"hello", &buffer); 94 /// 95 /// // Note that while this is safe care must be taken because the indexing 96 /// // here may panic if the memory isn't large enough. 97 /// assert_eq!(&mem.data(&store)[offset..offset + 5], b"hello"); 98 /// mem.data_mut(&mut *store)[offset..offset + 5].copy_from_slice(b"bye!!"); 99 /// 100 /// Ok(()) 101 /// } 102 /// ``` 103 /// 104 /// It's worth also, however, covering some examples of **incorrect**, 105 /// **unsafe** usages of `Memory`. Do not do these things! 106 /// 107 /// ```rust 108 /// # use anyhow::Result; 109 /// use wasmtime::{Memory, Store}; 110 /// 111 /// // NOTE: All code in this function is not safe to execute and may cause 112 /// // segfaults/undefined behavior at runtime. Do not copy/paste these examples 113 /// // into production code! 114 /// unsafe fn unsafe_examples(mem: Memory, store: &mut Store<()>) -> Result<()> { 115 /// // First and foremost, any borrow can be invalidated at any time via the 116 /// // `Memory::grow` function. This can relocate memory which causes any 117 /// // previous pointer to be possibly invalid now. 118 /// unsafe { 119 /// let pointer: &u8 = &*mem.data_ptr(&store); 120 /// mem.grow(&mut *store, 1)?; // invalidates `pointer`! 121 /// // println!("{}", *pointer); // FATAL: use-after-free 122 /// } 123 /// 124 /// // Note that the use-after-free also applies to slices, whether they're 125 /// // slices of bytes or strings. 126 /// unsafe { 127 /// let mem_slice = std::slice::from_raw_parts( 128 /// mem.data_ptr(&store), 129 /// mem.data_size(&store), 130 /// ); 131 /// let slice: &[u8] = &mem_slice[0x100..0x102]; 132 /// mem.grow(&mut *store, 1)?; // invalidates `slice`! 133 /// // println!("{:?}", slice); // FATAL: use-after-free 134 /// } 135 /// 136 /// // The `Memory` type may be stored in other locations, so if you hand 137 /// // off access to the `Store` then those locations may also call 138 /// // `Memory::grow` or similar, so it's not enough to just audit code for 139 /// // calls to `Memory::grow`. 140 /// unsafe { 141 /// let pointer: &u8 = &*mem.data_ptr(&store); 142 /// some_other_function(store); // may invalidate `pointer` through use of `store` 143 /// // println!("{:?}", pointer); // FATAL: maybe a use-after-free 144 /// } 145 /// 146 /// // An especially subtle aspect of accessing a wasm instance's memory is 147 /// // that you need to be extremely careful about aliasing. Anyone at any 148 /// // time can call `data_unchecked()` or `data_unchecked_mut()`, which 149 /// // means you can easily have aliasing mutable references: 150 /// unsafe { 151 /// let ref1: &u8 = &*mem.data_ptr(&store).add(0x100); 152 /// let ref2: &mut u8 = &mut *mem.data_ptr(&store).add(0x100); 153 /// // *ref2 = *ref1; // FATAL: violates Rust's aliasing rules 154 /// } 155 /// 156 /// Ok(()) 157 /// } 158 /// # fn some_other_function(store: &mut Store<()>) {} 159 /// ``` 160 /// 161 /// Overall there's some general rules of thumb when unsafely working with 162 /// `Memory` and getting raw pointers inside of it: 163 /// 164 /// * If you never have a "long lived" pointer into memory, you're likely in the 165 /// clear. Care still needs to be taken in threaded scenarios or when/where 166 /// data is read, but you'll be shielded from many classes of issues. 167 /// * Long-lived pointers must always respect Rust'a aliasing rules. It's ok for 168 /// shared borrows to overlap with each other, but mutable borrows must 169 /// overlap with nothing. 170 /// * Long-lived pointers are only valid if they're not invalidated for their 171 /// lifetime. This means that [`Store`](crate::Store) isn't used to reenter 172 /// wasm or the memory itself is never grown or otherwise modified/aliased. 173 /// 174 /// At this point it's worth reiterating again that unsafely working with 175 /// `Memory` is pretty tricky and not recommended! It's highly recommended to 176 /// use the safe methods to interact with [`Memory`] whenever possible. 177 /// 178 /// ## `Memory` Safety and Threads 179 /// 180 /// Currently the `wasmtime` crate does not implement the wasm threads proposal, 181 /// but it is planned to do so. It may be interesting to readers to see how this 182 /// affects memory safety and what was previously just discussed as well. 183 /// 184 /// Once threads are added into the mix, all of the above rules still apply. 185 /// There's an additional consideration that all reads and writes can happen 186 /// concurrently, though. This effectively means that any borrow into wasm 187 /// memory are virtually never safe to have. 188 /// 189 /// Mutable pointers are fundamentally unsafe to have in a concurrent scenario 190 /// in the face of arbitrary wasm code. Only if you dynamically know for sure 191 /// that wasm won't access a region would it be safe to construct a mutable 192 /// pointer. Additionally even shared pointers are largely unsafe because their 193 /// underlying contents may change, so unless `UnsafeCell` in one form or 194 /// another is used everywhere there's no safety. 195 /// 196 /// One important point about concurrency is that while [`Memory::grow`] can 197 /// happen concurrently it will never relocate the base pointer. Shared 198 /// memories must always have a maximum size and they will be preallocated such 199 /// that growth will never relocate the base pointer. The current size of the 200 /// memory may still change over time though. 201 /// 202 /// Overall the general rule of thumb for shared memories is that you must 203 /// atomically read and write everything. Nothing can be borrowed and everything 204 /// must be eagerly copied out. This means that [`Memory::data`] and 205 /// [`Memory::data_mut`] won't work in the future (they'll probably return an 206 /// error) for shared memories when they're implemented. When possible it's 207 /// recommended to use [`Memory::read`] and [`Memory::write`] which will still 208 /// be provided. 209 #[derive(Copy, Clone, Debug)] 210 #[repr(C)] // here for the C API 211 pub struct Memory { 212 /// The internal store instance that this memory belongs to. 213 instance: StoreInstanceId, 214 /// The index of the memory, within `instance` above, that this memory 215 /// refers to. 216 index: DefinedMemoryIndex, 217 } 218 219 // Double-check that the C representation in `extern.h` matches our in-Rust 220 // representation here in terms of size/alignment/etc. 221 const _: () = { 222 #[repr(C)] 223 struct Tmp(u64, u32); 224 #[repr(C)] 225 struct C(Tmp, u32); 226 assert!(core::mem::size_of::<C>() == core::mem::size_of::<Memory>()); 227 assert!(core::mem::align_of::<C>() == core::mem::align_of::<Memory>()); 228 assert!(core::mem::offset_of!(Memory, instance) == 0); 229 }; 230 231 impl Memory { 232 /// Creates a new WebAssembly memory given the configuration of `ty`. 233 /// 234 /// The `store` argument will be the owner of the returned [`Memory`]. All 235 /// WebAssembly memory is initialized to zero. 236 /// 237 /// # Panics 238 /// 239 /// This function will panic if the [`Store`](`crate::Store`) has a 240 /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`) (see also: 241 /// [`Store::limiter_async`](`crate::Store::limiter_async`)). When 242 /// using an async resource limiter, use [`Memory::new_async`] instead. 243 /// 244 /// # Examples 245 /// 246 /// ``` 247 /// # use wasmtime::*; 248 /// # fn main() -> anyhow::Result<()> { 249 /// let engine = Engine::default(); 250 /// let mut store = Store::new(&engine, ()); 251 /// 252 /// let memory_ty = MemoryType::new(1, None); 253 /// let memory = Memory::new(&mut store, memory_ty)?; 254 /// 255 /// let module = Module::new(&engine, "(module (memory (import \"\" \"\") 1))")?; 256 /// let instance = Instance::new(&mut store, &module, &[memory.into()])?; 257 /// // ... 258 /// # Ok(()) 259 /// # } 260 /// ``` 261 pub fn new(mut store: impl AsContextMut, ty: MemoryType) -> Result<Memory> { 262 Self::_new(store.as_context_mut().0, ty) 263 } 264 265 /// Async variant of [`Memory::new`]. You must use this variant with 266 /// [`Store`](`crate::Store`)s which have a 267 /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`). 268 /// 269 /// # Panics 270 /// 271 /// This function will panic when used with a non-async 272 /// [`Store`](`crate::Store`). 273 #[cfg(feature = "async")] 274 pub async fn new_async( 275 mut store: impl AsContextMut<Data: Send>, 276 ty: MemoryType, 277 ) -> Result<Memory> { 278 let mut store = store.as_context_mut(); 279 assert!( 280 store.0.async_support(), 281 "cannot use `new_async` without enabling async support on the config" 282 ); 283 store.on_fiber(|store| Self::_new(store.0, ty)).await? 284 } 285 286 /// Helper function for attaching the memory to a "frankenstein" instance 287 fn _new(store: &mut StoreOpaque, ty: MemoryType) -> Result<Memory> { 288 generate_memory_export(store, &ty, None) 289 } 290 291 /// Returns the underlying type of this memory. 292 /// 293 /// # Panics 294 /// 295 /// Panics if this memory doesn't belong to `store`. 296 /// 297 /// # Examples 298 /// 299 /// ``` 300 /// # use wasmtime::*; 301 /// # fn main() -> anyhow::Result<()> { 302 /// let engine = Engine::default(); 303 /// let mut store = Store::new(&engine, ()); 304 /// let module = Module::new(&engine, "(module (memory (export \"mem\") 1))")?; 305 /// let instance = Instance::new(&mut store, &module, &[])?; 306 /// let memory = instance.get_memory(&mut store, "mem").unwrap(); 307 /// let ty = memory.ty(&store); 308 /// assert_eq!(ty.minimum(), 1); 309 /// # Ok(()) 310 /// # } 311 /// ``` 312 pub fn ty(&self, store: impl AsContext) -> MemoryType { 313 let store = store.as_context(); 314 MemoryType::from_wasmtime_memory(self.wasmtime_ty(store.0)) 315 } 316 317 /// Safely reads memory contents at the given offset into a buffer. 318 /// 319 /// The entire buffer will be filled. 320 /// 321 /// If `offset + buffer.len()` exceed the current memory capacity, then the 322 /// buffer is left untouched and a [`MemoryAccessError`] is returned. 323 /// 324 /// # Panics 325 /// 326 /// Panics if this memory doesn't belong to `store`. 327 pub fn read( 328 &self, 329 store: impl AsContext, 330 offset: usize, 331 buffer: &mut [u8], 332 ) -> Result<(), MemoryAccessError> { 333 let store = store.as_context(); 334 let slice = self 335 .data(&store) 336 .get(offset..) 337 .and_then(|s| s.get(..buffer.len())) 338 .ok_or(MemoryAccessError { _private: () })?; 339 buffer.copy_from_slice(slice); 340 Ok(()) 341 } 342 343 /// Safely writes contents of a buffer to this memory at the given offset. 344 /// 345 /// If the `offset + buffer.len()` exceeds the current memory capacity, then 346 /// none of the buffer is written to memory and a [`MemoryAccessError`] is 347 /// returned. 348 /// 349 /// # Panics 350 /// 351 /// Panics if this memory doesn't belong to `store`. 352 pub fn write( 353 &self, 354 mut store: impl AsContextMut, 355 offset: usize, 356 buffer: &[u8], 357 ) -> Result<(), MemoryAccessError> { 358 let mut context = store.as_context_mut(); 359 self.data_mut(&mut context) 360 .get_mut(offset..) 361 .and_then(|s| s.get_mut(..buffer.len())) 362 .ok_or(MemoryAccessError { _private: () })? 363 .copy_from_slice(buffer); 364 Ok(()) 365 } 366 367 /// Returns this memory as a native Rust slice. 368 /// 369 /// Note that this method will consider the entire store context provided as 370 /// borrowed for the duration of the lifetime of the returned slice. 371 /// 372 /// # Panics 373 /// 374 /// Panics if this memory doesn't belong to `store`. 375 pub fn data<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [u8] { 376 unsafe { 377 let store = store.into(); 378 let definition = store[self.instance].memory(self.index); 379 debug_assert!(!self.ty(store).is_shared()); 380 slice::from_raw_parts(definition.base.as_ptr(), definition.current_length()) 381 } 382 } 383 384 /// Returns this memory as a native Rust mutable slice. 385 /// 386 /// Note that this method will consider the entire store context provided as 387 /// borrowed for the duration of the lifetime of the returned slice. 388 /// 389 /// # Panics 390 /// 391 /// Panics if this memory doesn't belong to `store`. 392 pub fn data_mut<'a, T: 'static>( 393 &self, 394 store: impl Into<StoreContextMut<'a, T>>, 395 ) -> &'a mut [u8] { 396 unsafe { 397 let store = store.into(); 398 let definition = store[self.instance].memory(self.index); 399 debug_assert!(!self.ty(store).is_shared()); 400 slice::from_raw_parts_mut(definition.base.as_ptr(), definition.current_length()) 401 } 402 } 403 404 /// Same as [`Memory::data_mut`], but also returns the `T` from the 405 /// [`StoreContextMut`]. 406 /// 407 /// This method can be used when you want to simultaneously work with the 408 /// `T` in the store as well as the memory behind this [`Memory`]. Using 409 /// [`Memory::data_mut`] would consider the entire store borrowed, whereas 410 /// this method allows the Rust compiler to see that the borrow of this 411 /// memory and the borrow of `T` are disjoint. 412 /// 413 /// # Panics 414 /// 415 /// Panics if this memory doesn't belong to `store`. 416 pub fn data_and_store_mut<'a, T: 'static>( 417 &self, 418 store: impl Into<StoreContextMut<'a, T>>, 419 ) -> (&'a mut [u8], &'a mut T) { 420 // Note the unsafety here. Our goal is to simultaneously borrow the 421 // memory and custom data from `store`, and the store it's connected 422 // to. Rust will not let us do that, however, because we must call two 423 // separate methods (both of which borrow the whole `store`) and one of 424 // our borrows is mutable (the custom data). 425 // 426 // This operation, however, is safe because these borrows do not overlap 427 // and in the process of borrowing them mutability doesn't actually 428 // touch anything. This is akin to mutably borrowing two indices in an 429 // array, which is safe so long as the indices are separate. 430 unsafe { 431 let mut store = store.into(); 432 let data = &mut *(store.data_mut() as *mut T); 433 (self.data_mut(store), data) 434 } 435 } 436 437 /// Returns the base pointer, in the host's address space, that the memory 438 /// is located at. 439 /// 440 /// For more information and examples see the documentation on the 441 /// [`Memory`] type. 442 /// 443 /// # Panics 444 /// 445 /// Panics if this memory doesn't belong to `store`. 446 pub fn data_ptr(&self, store: impl AsContext) -> *mut u8 { 447 store.as_context()[self.instance] 448 .memory(self.index) 449 .base 450 .as_ptr() 451 } 452 453 /// Returns the byte length of this memory. 454 /// 455 /// WebAssembly memories are made up of a whole number of pages, so the byte 456 /// size returned will always be a multiple of this memory's page size. Note 457 /// that different Wasm memories may have different page sizes. You can get 458 /// a memory's page size via the [`Memory::page_size`] method. 459 /// 460 /// By default the page size is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or 461 /// `65536`) but [the custom-page-sizes proposal] allows a memory to opt 462 /// into a page size of `1`. Future extensions might allow any power of two 463 /// as a page size. 464 /// 465 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes 466 /// 467 /// For more information and examples see the documentation on the 468 /// [`Memory`] type. 469 /// 470 /// # Panics 471 /// 472 /// Panics if this memory doesn't belong to `store`. 473 pub fn data_size(&self, store: impl AsContext) -> usize { 474 self.internal_data_size(store.as_context().0) 475 } 476 477 pub(crate) fn internal_data_size(&self, store: &StoreOpaque) -> usize { 478 store[self.instance].memory(self.index).current_length() 479 } 480 481 /// Returns the size, in units of pages, of this Wasm memory. 482 /// 483 /// WebAssembly memories are made up of a whole number of pages, so the byte 484 /// size returned will always be a multiple of this memory's page size. Note 485 /// that different Wasm memories may have different page sizes. You can get 486 /// a memory's page size via the [`Memory::page_size`] method. 487 /// 488 /// By default the page size is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or 489 /// `65536`) but [the custom-page-sizes proposal] allows a memory to opt 490 /// into a page size of `1`. Future extensions might allow any power of two 491 /// as a page size. 492 /// 493 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes 494 /// 495 /// # Panics 496 /// 497 /// Panics if this memory doesn't belong to `store`. 498 pub fn size(&self, store: impl AsContext) -> u64 { 499 self.internal_size(store.as_context().0) 500 } 501 502 pub(crate) fn internal_size(&self, store: &StoreOpaque) -> u64 { 503 let byte_size = self.internal_data_size(store); 504 let page_size = usize::try_from(self._page_size(store)).unwrap(); 505 u64::try_from(byte_size / page_size).unwrap() 506 } 507 508 /// Returns the size of a page, in bytes, for this memory. 509 /// 510 /// WebAssembly memories are made up of a whole number of pages, so the byte 511 /// size (as returned by [`Memory::data_size`]) will always be a multiple of 512 /// their page size. Different Wasm memories may have different page sizes. 513 /// 514 /// By default this is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or `65536`) 515 /// but [the custom-page-sizes proposal] allows opting into a page size of 516 /// `1`. Future extensions might allow any power of two as a page size. 517 /// 518 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes 519 pub fn page_size(&self, store: impl AsContext) -> u64 { 520 self._page_size(store.as_context().0) 521 } 522 523 pub(crate) fn _page_size(&self, store: &StoreOpaque) -> u64 { 524 self.wasmtime_ty(store).page_size() 525 } 526 527 /// Returns the log2 of this memory's page size, in bytes. 528 /// 529 /// WebAssembly memories are made up of a whole number of pages, so the byte 530 /// size (as returned by [`Memory::data_size`]) will always be a multiple of 531 /// their page size. Different Wasm memories may have different page sizes. 532 /// 533 /// By default the page size is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or 534 /// `65536`) but [the custom-page-sizes proposal] allows opting into a page 535 /// size of `1`. Future extensions might allow any power of two as a page 536 /// size. 537 /// 538 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes 539 pub fn page_size_log2(&self, store: impl AsContext) -> u8 { 540 self._page_size_log2(store.as_context().0) 541 } 542 543 pub(crate) fn _page_size_log2(&self, store: &StoreOpaque) -> u8 { 544 self.wasmtime_ty(store).page_size_log2 545 } 546 547 /// Grows this WebAssembly memory by `delta` pages. 548 /// 549 /// This will attempt to add `delta` more pages of memory on to the end of 550 /// this `Memory` instance. If successful this may relocate the memory and 551 /// cause [`Memory::data_ptr`] to return a new value. Additionally any 552 /// unsafely constructed slices into this memory may no longer be valid. 553 /// 554 /// On success returns the number of pages this memory previously had 555 /// before the growth succeeded. 556 /// 557 /// Note that, by default, a WebAssembly memory's page size is 64KiB (aka 558 /// 65536 or 2<sup>16</sup>). The [custom-page-sizes proposal] allows Wasm 559 /// memories to opt into a page size of one byte (and this may be further 560 /// relaxed to any power of two in a future extension). 561 /// 562 /// [custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes 563 /// 564 /// # Errors 565 /// 566 /// Returns an error if memory could not be grown, for example if it exceeds 567 /// the maximum limits of this memory. A 568 /// [`ResourceLimiter`](crate::ResourceLimiter) is another example of 569 /// preventing a memory to grow. 570 /// 571 /// # Panics 572 /// 573 /// Panics if this memory doesn't belong to `store`. 574 /// 575 /// This function will panic if the [`Store`](`crate::Store`) has a 576 /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`) (see also: 577 /// [`Store::limiter_async`](`crate::Store::limiter_async`). When using an 578 /// async resource limiter, use [`Memory::grow_async`] instead. 579 /// 580 /// # Examples 581 /// 582 /// ``` 583 /// # use wasmtime::*; 584 /// # fn main() -> anyhow::Result<()> { 585 /// let engine = Engine::default(); 586 /// let mut store = Store::new(&engine, ()); 587 /// let module = Module::new(&engine, "(module (memory (export \"mem\") 1 2))")?; 588 /// let instance = Instance::new(&mut store, &module, &[])?; 589 /// let memory = instance.get_memory(&mut store, "mem").unwrap(); 590 /// 591 /// assert_eq!(memory.size(&store), 1); 592 /// assert_eq!(memory.grow(&mut store, 1)?, 1); 593 /// assert_eq!(memory.size(&store), 2); 594 /// assert!(memory.grow(&mut store, 1).is_err()); 595 /// assert_eq!(memory.size(&store), 2); 596 /// assert_eq!(memory.grow(&mut store, 0)?, 2); 597 /// # Ok(()) 598 /// # } 599 /// ``` 600 pub fn grow(&self, mut store: impl AsContextMut, delta: u64) -> Result<u64> { 601 let store = store.as_context_mut().0; 602 // FIXME(#11179) shouldn't use a raw pointer to work around the borrow 603 // checker here. 604 let mem: *mut _ = self.wasmtime_memory(store); 605 unsafe { 606 match (*mem).grow(delta, Some(store))? { 607 Some(size) => { 608 let vm = (*mem).vmmemory(); 609 store[self.instance].memory_ptr(self.index).write(vm); 610 let page_size = (*mem).page_size(); 611 Ok(u64::try_from(size).unwrap() / page_size) 612 } 613 None => bail!("failed to grow memory by `{}`", delta), 614 } 615 } 616 } 617 618 /// Async variant of [`Memory::grow`]. Required when using a 619 /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`). 620 /// 621 /// # Panics 622 /// 623 /// This function will panic when used with a non-async 624 /// [`Store`](`crate::Store`). 625 #[cfg(feature = "async")] 626 pub async fn grow_async( 627 &self, 628 mut store: impl AsContextMut<Data: Send>, 629 delta: u64, 630 ) -> Result<u64> { 631 let mut store = store.as_context_mut(); 632 assert!( 633 store.0.async_support(), 634 "cannot use `grow_async` without enabling async support on the config" 635 ); 636 store.on_fiber(|store| self.grow(store, delta)).await? 637 } 638 639 fn wasmtime_memory<'a>( 640 &self, 641 store: &'a mut StoreOpaque, 642 ) -> &'a mut crate::runtime::vm::Memory { 643 self.instance 644 .get_mut(store) 645 .get_defined_memory_mut(self.index) 646 } 647 648 pub(crate) fn from_raw(instance: StoreInstanceId, index: DefinedMemoryIndex) -> Memory { 649 Memory { instance, index } 650 } 651 652 pub(crate) fn wasmtime_ty<'a>(&self, store: &'a StoreOpaque) -> &'a wasmtime_environ::Memory { 653 let module = store[self.instance].env_module(); 654 let index = module.memory_index(self.index); 655 &module.memories[index] 656 } 657 658 pub(crate) fn vmimport(&self, store: &StoreOpaque) -> crate::runtime::vm::VMMemoryImport { 659 let instance = &store[self.instance]; 660 crate::runtime::vm::VMMemoryImport { 661 from: instance.memory_ptr(self.index).into(), 662 vmctx: instance.vmctx().into(), 663 index: self.index, 664 } 665 } 666 667 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 668 store.id() == self.instance.store_id() 669 } 670 671 /// Get a stable hash key for this memory. 672 /// 673 /// Even if the same underlying memory definition is added to the 674 /// `StoreData` multiple times and becomes multiple `wasmtime::Memory`s, 675 /// this hash key will be consistent across all of these memories. 676 #[cfg(feature = "coredump")] 677 pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl core::hash::Hash + Eq + use<> { 678 store[self.instance].memory_ptr(self.index).as_ptr().addr() 679 } 680 } 681 682 /// A linear memory. This trait provides an interface for raw memory buffers 683 /// which are used by wasmtime, e.g. inside ['Memory']. Such buffers are in 684 /// principle not thread safe. By implementing this trait together with 685 /// MemoryCreator, one can supply wasmtime with custom allocated host managed 686 /// memory. 687 /// 688 /// # Safety 689 /// 690 /// The memory should be page aligned and a multiple of page size. 691 /// To prevent possible silent overflows, the memory should be protected by a 692 /// guard page. Additionally the safety concerns explained in ['Memory'], for 693 /// accessing the memory apply here as well. 694 /// 695 /// Note that this is a relatively advanced feature and it is recommended to be 696 /// familiar with wasmtime runtime code to use it. 697 pub unsafe trait LinearMemory: Send + Sync + 'static { 698 /// Returns the number of allocated bytes which are accessible at this time. 699 fn byte_size(&self) -> usize; 700 701 /// Returns byte capacity of this linear memory's current allocation. 702 /// 703 /// Growth up to this value should not relocate the linear memory base 704 /// pointer. 705 fn byte_capacity(&self) -> usize; 706 707 /// Grows this memory to have the `new_size`, in bytes, specified. 708 /// 709 /// Returns `Err` if memory can't be grown by the specified amount 710 /// of bytes. The error may be downcastable to `std::io::Error`. 711 /// Returns `Ok` if memory was grown successfully. 712 fn grow_to(&mut self, new_size: usize) -> Result<()>; 713 714 /// Return the allocated memory as a mutable pointer to u8. 715 fn as_ptr(&self) -> *mut u8; 716 } 717 718 /// A memory creator. Can be used to provide a memory creator 719 /// to wasmtime which supplies host managed memory. 720 /// 721 /// # Safety 722 /// 723 /// This trait is unsafe, as the memory safety depends on proper implementation 724 /// of memory management. Memories created by the MemoryCreator should always be 725 /// treated as owned by wasmtime instance, and any modification of them outside 726 /// of wasmtime invoked routines is unsafe and may lead to corruption. 727 /// 728 /// Note that this is a relatively advanced feature and it is recommended to be 729 /// familiar with Wasmtime runtime code to use it. 730 pub unsafe trait MemoryCreator: Send + Sync { 731 /// Create a new `LinearMemory` object from the specified parameters. 732 /// 733 /// The type of memory being created is specified by `ty` which indicates 734 /// both the minimum and maximum size, in wasm pages. The minimum and 735 /// maximum sizes, in bytes, are also specified as parameters to avoid 736 /// integer conversion if desired. 737 /// 738 /// The `reserved_size_in_bytes` value indicates the expected size of the 739 /// reservation that is to be made for this memory. If this value is `None` 740 /// than the implementation is free to allocate memory as it sees fit. If 741 /// the value is `Some`, however, then the implementation is expected to 742 /// reserve that many bytes for the memory's allocation, plus the guard 743 /// size at the end. Note that this reservation need only be a virtual 744 /// memory reservation, physical memory does not need to be allocated 745 /// immediately. In this case `grow` should never move the base pointer and 746 /// the maximum size of `ty` is guaranteed to fit within 747 /// `reserved_size_in_bytes`. 748 /// 749 /// The `guard_size_in_bytes` parameter indicates how many bytes of space, 750 /// after the memory allocation, is expected to be unmapped. JIT code will 751 /// elide bounds checks based on the `guard_size_in_bytes` provided, so for 752 /// JIT code to work correctly the memory returned will need to be properly 753 /// guarded with `guard_size_in_bytes` bytes left unmapped after the base 754 /// allocation. 755 /// 756 /// Note that the `reserved_size_in_bytes` and `guard_size_in_bytes` options 757 /// are tuned from the various [`Config`](crate::Config) methods about 758 /// memory sizes/guards. Additionally these two values are guaranteed to be 759 /// multiples of the system page size. 760 /// 761 /// Memory created from this method should be zero filled. 762 fn new_memory( 763 &self, 764 ty: MemoryType, 765 minimum: usize, 766 maximum: Option<usize>, 767 reserved_size_in_bytes: Option<usize>, 768 guard_size_in_bytes: usize, 769 ) -> Result<Box<dyn LinearMemory>, String>; 770 } 771 772 /// A constructor for externally-created shared memory. 773 /// 774 /// The [threads proposal] adds the concept of "shared memory" to WebAssembly. 775 /// This is much the same as a Wasm linear memory (i.e., [`Memory`]), but can be 776 /// used concurrently by multiple agents. Because these agents may execute in 777 /// different threads, [`SharedMemory`] must be thread-safe. 778 /// 779 /// When the threads proposal is enabled, there are multiple ways to construct 780 /// shared memory: 781 /// 1. for imported shared memory, e.g., `(import "env" "memory" (memory 1 1 782 /// shared))`, the user must supply a [`SharedMemory`] with the 783 /// externally-created memory as an import to the instance--e.g., 784 /// `shared_memory.into()`. 785 /// 2. for private or exported shared memory, e.g., `(export "env" "memory" 786 /// (memory 1 1 shared))`, Wasmtime will create the memory internally during 787 /// instantiation--access using `Instance::get_shared_memory()`. 788 /// 789 /// [threads proposal]: 790 /// https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md 791 /// 792 /// # Examples 793 /// 794 /// ``` 795 /// # use wasmtime::*; 796 /// # fn main() -> anyhow::Result<()> { 797 /// let mut config = Config::new(); 798 /// config.wasm_threads(true); 799 /// let engine = Engine::new(&config)?; 800 /// let mut store = Store::new(&engine, ()); 801 /// 802 /// let shared_memory = SharedMemory::new(&engine, MemoryType::shared(1, 2))?; 803 /// let module = Module::new(&engine, r#"(module (memory (import "" "") 1 2 shared))"#)?; 804 /// let instance = Instance::new(&mut store, &module, &[shared_memory.into()])?; 805 /// // ... 806 /// # Ok(()) 807 /// # } 808 /// ``` 809 #[derive(Clone)] 810 pub struct SharedMemory { 811 vm: crate::runtime::vm::SharedMemory, 812 engine: Engine, 813 page_size_log2: u8, 814 } 815 816 impl SharedMemory { 817 /// Construct a [`SharedMemory`] by providing both the `minimum` and 818 /// `maximum` number of 64K-sized pages. This call allocates the necessary 819 /// pages on the system. 820 #[cfg(feature = "threads")] 821 pub fn new(engine: &Engine, ty: MemoryType) -> Result<Self> { 822 if !ty.is_shared() { 823 bail!("shared memory must have the `shared` flag enabled on its memory type") 824 } 825 debug_assert!(ty.maximum().is_some()); 826 827 let tunables = engine.tunables(); 828 let ty = ty.wasmtime_memory(); 829 let page_size_log2 = ty.page_size_log2; 830 let memory = crate::runtime::vm::SharedMemory::new(ty, tunables)?; 831 832 Ok(Self { 833 vm: memory, 834 engine: engine.clone(), 835 page_size_log2, 836 }) 837 } 838 839 /// Return the type of the shared memory. 840 pub fn ty(&self) -> MemoryType { 841 MemoryType::from_wasmtime_memory(&self.vm.ty()) 842 } 843 844 /// Returns the size, in WebAssembly pages, of this wasm memory. 845 pub fn size(&self) -> u64 { 846 let byte_size = u64::try_from(self.data_size()).unwrap(); 847 let page_size = u64::from(self.page_size()); 848 byte_size / page_size 849 } 850 851 /// Returns the size of a page, in bytes, for this memory. 852 /// 853 /// By default this is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or `65536`) 854 /// but [the custom-page-sizes proposal] allows opting into a page size of 855 /// `1`. Future extensions might allow any power of two as a page size. 856 /// 857 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes 858 pub fn page_size(&self) -> u32 { 859 debug_assert!(self.page_size_log2 == 0 || self.page_size_log2 == 16); 860 1 << self.page_size_log2 861 } 862 863 /// Returns the byte length of this memory. 864 /// 865 /// The returned value will be a multiple of the wasm page size, 64k. 866 /// 867 /// For more information and examples see the documentation on the 868 /// [`Memory`] type. 869 pub fn data_size(&self) -> usize { 870 self.vm.byte_size() 871 } 872 873 /// Return access to the available portion of the shared memory. 874 /// 875 /// The slice returned represents the region of accessible memory at the 876 /// time that this function was called. The contents of the returned slice 877 /// will reflect concurrent modifications happening on other threads. 878 /// 879 /// # Safety 880 /// 881 /// The returned slice is valid for the entire duration of the lifetime of 882 /// this instance of [`SharedMemory`]. The base pointer of a shared memory 883 /// does not change. This [`SharedMemory`] may grow further after this 884 /// function has been called, but the slice returned will not grow. 885 /// 886 /// Concurrent modifications may be happening to the data returned on other 887 /// threads. The `UnsafeCell<u8>` represents that safe access to the 888 /// contents of the slice is not possible through normal loads and stores. 889 /// 890 /// The memory returned must be accessed safely through the `Atomic*` types 891 /// in the [`std::sync::atomic`] module. Casting to those types must 892 /// currently be done unsafely. 893 pub fn data(&self) -> &[UnsafeCell<u8>] { 894 unsafe { 895 let definition = self.vm.vmmemory_ptr().as_ref(); 896 slice::from_raw_parts(definition.base.as_ptr().cast(), definition.current_length()) 897 } 898 } 899 900 /// Grows this WebAssembly memory by `delta` pages. 901 /// 902 /// This will attempt to add `delta` more pages of memory on to the end of 903 /// this `Memory` instance. If successful this may relocate the memory and 904 /// cause [`Memory::data_ptr`] to return a new value. Additionally any 905 /// unsafely constructed slices into this memory may no longer be valid. 906 /// 907 /// On success returns the number of pages this memory previously had 908 /// before the growth succeeded. 909 /// 910 /// # Errors 911 /// 912 /// Returns an error if memory could not be grown, for example if it exceeds 913 /// the maximum limits of this memory. A 914 /// [`ResourceLimiter`](crate::ResourceLimiter) is another example of 915 /// preventing a memory to grow. 916 pub fn grow(&self, delta: u64) -> Result<u64> { 917 match self.vm.grow(delta, None)? { 918 Some((old_size, _new_size)) => { 919 // For shared memory, the `VMMemoryDefinition` is updated inside 920 // the locked region. 921 Ok(u64::try_from(old_size).unwrap() / u64::from(self.page_size())) 922 } 923 None => bail!("failed to grow memory by `{}`", delta), 924 } 925 } 926 927 /// Equivalent of the WebAssembly `memory.atomic.notify` instruction for 928 /// this shared memory. 929 /// 930 /// This method allows embedders to notify threads blocked on the specified 931 /// `addr`, an index into wasm linear memory. Threads could include 932 /// wasm threads blocked on a `memory.atomic.wait*` instruction or embedder 933 /// threads blocked on [`SharedMemory::atomic_wait32`], for example. 934 /// 935 /// The `count` argument is the number of threads to wake up. 936 /// 937 /// This function returns the number of threads awoken. 938 /// 939 /// # Errors 940 /// 941 /// This function will return an error if `addr` is not within bounds or 942 /// not aligned to a 4-byte boundary. 943 pub fn atomic_notify(&self, addr: u64, count: u32) -> Result<u32, Trap> { 944 self.vm.atomic_notify(addr, count) 945 } 946 947 /// Equivalent of the WebAssembly `memory.atomic.wait32` instruction for 948 /// this shared memory. 949 /// 950 /// This method allows embedders to block the current thread until notified 951 /// via the `memory.atomic.notify` instruction or the 952 /// [`SharedMemory::atomic_notify`] method, enabling synchronization with 953 /// the wasm guest as desired. 954 /// 955 /// The `expected` argument is the expected 32-bit value to be stored at 956 /// the byte address `addr` specified. The `addr` specified is an index 957 /// into this linear memory. 958 /// 959 /// The optional `timeout` argument is the maximum amount of time to block 960 /// the current thread. If not specified the thread may sleep indefinitely. 961 /// 962 /// This function returns one of three possible values: 963 /// 964 /// * `WaitResult::Ok` - this function, loaded the value at `addr`, found 965 /// it was equal to `expected`, and then blocked (all as one atomic 966 /// operation). The thread was then awoken with a `memory.atomic.notify` 967 /// instruction or the [`SharedMemory::atomic_notify`] method. 968 /// * `WaitResult::Mismatch` - the value at `addr` was loaded but was not 969 /// equal to `expected` so the thread did not block and immediately 970 /// returned. 971 /// * `WaitResult::TimedOut` - all the steps of `Ok` happened, except this 972 /// thread was woken up due to a timeout. 973 /// 974 /// This function will not return due to spurious wakeups. 975 /// 976 /// # Errors 977 /// 978 /// This function will return an error if `addr` is not within bounds or 979 /// not aligned to a 4-byte boundary. 980 pub fn atomic_wait32( 981 &self, 982 addr: u64, 983 expected: u32, 984 timeout: Option<Duration>, 985 ) -> Result<WaitResult, Trap> { 986 self.vm.atomic_wait32(addr, expected, timeout) 987 } 988 989 /// Equivalent of the WebAssembly `memory.atomic.wait64` instruction for 990 /// this shared memory. 991 /// 992 /// For more information see [`SharedMemory::atomic_wait32`]. 993 /// 994 /// # Errors 995 /// 996 /// Returns the same error as [`SharedMemory::atomic_wait32`] except that 997 /// the specified address must be 8-byte aligned instead of 4-byte aligned. 998 pub fn atomic_wait64( 999 &self, 1000 addr: u64, 1001 expected: u64, 1002 timeout: Option<Duration>, 1003 ) -> Result<WaitResult, Trap> { 1004 self.vm.atomic_wait64(addr, expected, timeout) 1005 } 1006 1007 /// Return a reference to the [`Engine`] used to configure the shared 1008 /// memory. 1009 pub(crate) fn engine(&self) -> &Engine { 1010 &self.engine 1011 } 1012 1013 /// Construct a single-memory instance to provide a way to import 1014 /// [`SharedMemory`] into other modules. 1015 pub(crate) fn vmimport(&self, store: &mut StoreOpaque) -> crate::runtime::vm::VMMemoryImport { 1016 generate_memory_export(store, &self.ty(), Some(&self.vm)) 1017 .unwrap() 1018 .vmimport(store) 1019 } 1020 1021 /// Create a [`SharedMemory`] from an [`ExportMemory`] definition. This 1022 /// function is available to handle the case in which a Wasm module exports 1023 /// shared memory and the user wants host-side access to it. 1024 pub(crate) fn from_memory(mem: Memory, store: &StoreOpaque) -> Self { 1025 #![cfg_attr( 1026 not(feature = "threads"), 1027 expect( 1028 unused_variables, 1029 unreachable_code, 1030 reason = "definitions cfg'd to dummy", 1031 ) 1032 )] 1033 1034 let instance = mem.instance.get(store); 1035 let memory = instance.get_defined_memory(mem.index); 1036 let module = instance.env_module(); 1037 let page_size_log2 = module.memories[module.memory_index(mem.index)].page_size_log2; 1038 match memory.as_shared_memory() { 1039 Some(mem) => Self { 1040 vm: mem.clone(), 1041 engine: store.engine().clone(), 1042 page_size_log2, 1043 }, 1044 None => panic!("unable to convert from a shared memory"), 1045 } 1046 } 1047 } 1048 1049 impl fmt::Debug for SharedMemory { 1050 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1051 f.debug_struct("SharedMemory").finish_non_exhaustive() 1052 } 1053 } 1054 1055 #[cfg(test)] 1056 mod tests { 1057 use crate::*; 1058 1059 // Assert that creating a memory via `Memory::new` respects the limits/tunables 1060 // in `Config`. 1061 #[test] 1062 fn respect_tunables() { 1063 let mut cfg = Config::new(); 1064 cfg.memory_reservation(0).memory_guard_size(0); 1065 let mut store = Store::new(&Engine::new(&cfg).unwrap(), ()); 1066 let ty = MemoryType::new(1, None); 1067 let mem = Memory::new(&mut store, ty).unwrap(); 1068 let store = store.as_context(); 1069 let tunables = store.engine().tunables(); 1070 assert_eq!(tunables.memory_guard_size, 0); 1071 assert!( 1072 !mem.wasmtime_ty(store.0) 1073 .can_elide_bounds_check(tunables, 12) 1074 ); 1075 } 1076 1077 #[test] 1078 fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> { 1079 let mut store = Store::<()>::default(); 1080 let module = Module::new( 1081 store.engine(), 1082 r#" 1083 (module 1084 (memory (export "m") 1 1) 1085 ) 1086 "#, 1087 )?; 1088 let instance = Instance::new(&mut store, &module, &[])?; 1089 1090 // Each time we `get_memory`, we call `Memory::from_wasmtime` which adds 1091 // a new entry to `StoreData`, so `g1` and `g2` will have different 1092 // indices into `StoreData`. 1093 let m1 = instance.get_memory(&mut store, "m").unwrap(); 1094 let m2 = instance.get_memory(&mut store, "m").unwrap(); 1095 1096 // That said, they really point to the same memory. 1097 assert_eq!(m1.data(&store)[0], 0); 1098 assert_eq!(m2.data(&store)[0], 0); 1099 m1.data_mut(&mut store)[0] = 42; 1100 assert_eq!(m1.data(&mut store)[0], 42); 1101 assert_eq!(m2.data(&mut store)[0], 42); 1102 1103 // And therefore their hash keys are the same. 1104 assert!(m1.hash_key(&store.as_context().0) == m2.hash_key(&store.as_context().0)); 1105 1106 // But the hash keys are different from different memories. 1107 let instance2 = Instance::new(&mut store, &module, &[])?; 1108 let m3 = instance2.get_memory(&mut store, "m").unwrap(); 1109 assert!(m1.hash_key(&store.as_context().0) != m3.hash_key(&store.as_context().0)); 1110 1111 Ok(()) 1112 } 1113 } 1114