1 mod rooting; 2 3 use anyhow::anyhow; 4 pub use rooting::*; 5 6 use crate::store::AutoAssertNoGc; 7 use crate::{AsContextMut, Result, StoreContext, StoreContextMut}; 8 use std::any::Any; 9 use std::ffi::c_void; 10 use wasmtime_runtime::VMExternRef; 11 12 /// An opaque, GC-managed reference to some host data that can be passed to 13 /// WebAssembly. 14 /// 15 /// The `ExternRef` type represents WebAssembly `externref` values. These are 16 /// opaque and unforgable to Wasm: they cannot be faked and Wasm can't, for 17 /// example, cast the integer `0x12345678` into a reference, pretend it is a 18 /// valid `externref`, and trick the host into dereferencing it and segfaulting 19 /// or worse. Wasm can't do anything with the `externref`s other than put them 20 /// in tables, globals, and locals or pass them to other functions. 21 /// 22 /// You can use `ExternRef` to give access to host objects and control the 23 /// operations that Wasm can perform on them via what functions you allow Wasm 24 /// to import. 25 /// 26 /// Note that you can also use `Rooted<ExternRef>` as a type parameter with 27 /// [`Func::typed`][crate::Func::typed]- and 28 /// [`Func::wrap`][crate::Func::wrap]-style APIs. 29 /// 30 /// # Example 31 /// 32 /// ``` 33 /// # use wasmtime::*; 34 /// # use std::borrow::Cow; 35 /// # fn _foo() -> Result<()> { 36 /// let engine = Engine::default(); 37 /// let mut store = Store::new(&engine, ()); 38 /// 39 /// // Define some APIs for working with host strings from Wasm via `externref`. 40 /// let mut linker = Linker::new(&engine); 41 /// linker.func_wrap( 42 /// "host-string", 43 /// "new", 44 /// |caller: Caller<'_, ()>| -> Rooted<ExternRef> { ExternRef::new(caller, Cow::from("")) }, 45 /// )?; 46 /// linker.func_wrap( 47 /// "host-string", 48 /// "concat", 49 /// |mut caller: Caller<'_, ()>, a: Rooted<ExternRef>, b: Rooted<ExternRef>| -> Result<Rooted<ExternRef>> { 50 /// let mut s = a 51 /// .data(&caller)? 52 /// .downcast_ref::<Cow<str>>() 53 /// .ok_or_else(|| Error::msg("externref was not a string"))? 54 /// .clone() 55 /// .into_owned(); 56 /// let b = b 57 /// .data(&caller)? 58 /// .downcast_ref::<Cow<str>>() 59 /// .ok_or_else(|| Error::msg("externref was not a string"))?; 60 /// s.push_str(&b); 61 /// Ok(ExternRef::new(&mut caller, s)) 62 /// }, 63 /// )?; 64 /// 65 /// // Here is a Wasm module that uses those APIs. 66 /// let module = Module::new( 67 /// &engine, 68 /// r#" 69 /// (module 70 /// (import "host-string" "concat" (func $concat (param externref externref) 71 /// (result externref))) 72 /// (func (export "run") (param externref externref) (result externref) 73 /// local.get 0 74 /// local.get 1 75 /// call $concat 76 /// ) 77 /// ) 78 /// "#, 79 /// )?; 80 /// 81 /// // Create a couple `externref`s wrapping `Cow<str>`s. 82 /// let hello = ExternRef::new(&mut store, Cow::from("Hello, ")); 83 /// let world = ExternRef::new(&mut store, Cow::from("World!")); 84 /// 85 /// // Instantiate the module and pass the `externref`s into it. 86 /// let instance = linker.instantiate(&mut store, &module)?; 87 /// let result = instance 88 /// .get_typed_func::<(Rooted<ExternRef>, Rooted<ExternRef>), Rooted<ExternRef>>(&mut store, "run")? 89 /// .call(&mut store, (hello, world))?; 90 /// 91 /// // The module should have concatenated the strings together! 92 /// assert_eq!( 93 /// result.data(&store)?.downcast_ref::<Cow<str>>().unwrap(), 94 /// "Hello, World!" 95 /// ); 96 /// # Ok(()) 97 /// # } 98 /// ``` 99 #[derive(Debug)] 100 #[repr(transparent)] 101 pub struct ExternRef { 102 inner: GcRootIndex, 103 } 104 105 unsafe impl GcRefImpl for ExternRef { 106 fn transmute_ref(index: &GcRootIndex) -> &Self { 107 // Safety: `ExternRef` is a newtype of a `GcRootIndex`. 108 let me: &Self = unsafe { std::mem::transmute(index) }; 109 110 // Assert we really are just a newtype of a `GcRootIndex`. 111 assert!(matches!( 112 me, 113 Self { 114 inner: GcRootIndex { .. }, 115 } 116 )); 117 118 me 119 } 120 } 121 122 impl ExternRef { 123 /// Creates a new instance of `ExternRef` wrapping the given value. 124 /// 125 /// The resulting value is automatically unrooted when the given `context`'s 126 /// scope is exited. See [`Rooted<T>`][crate::Rooted]'s documentation for 127 /// more details. 128 /// 129 /// # Example 130 /// 131 /// ``` 132 /// # use wasmtime::*; 133 /// # fn _foo() -> Result<()> { 134 /// let mut store = Store::<()>::default(); 135 /// 136 /// { 137 /// let mut scope = RootScope::new(&mut store); 138 /// 139 /// // Create an `externref` wrapping a `str`. 140 /// let externref = ExternRef::new(&mut scope, "hello!"); 141 /// 142 /// // Use `externref`... 143 /// } 144 /// 145 /// // The `externref` is automatically unrooted when we exit the scope. 146 /// # Ok(()) 147 /// # } 148 /// ``` 149 pub fn new<T>(mut context: impl AsContextMut, value: T) -> Rooted<ExternRef> 150 where 151 T: 'static + Any + Send + Sync, 152 { 153 // Safety: We proviode `VMExternRef`'s invariants via the way that 154 // `ExternRef` methods take `impl AsContext[Mut]` methods. 155 let inner = unsafe { VMExternRef::new(value) }; 156 157 let mut context = AutoAssertNoGc::new(context.as_context_mut().0); 158 159 // Safety: we just created the `VMExternRef` and are associating it with 160 // this store. 161 unsafe { Self::from_vm_extern_ref(&mut context, inner) } 162 } 163 164 /// Creates a new, manually-rooted instance of `ExternRef` wrapping the 165 /// given value. 166 /// 167 /// The resulting value must be manually unrooted, or else it will leak for 168 /// the entire duration of the store's lifetime. See 169 /// [`ManuallyRooted<T>`][crate::ManuallyRooted]'s documentation for more 170 /// details. 171 /// 172 /// # Example 173 /// 174 /// ``` 175 /// # use wasmtime::*; 176 /// # fn _foo() -> Result<()> { 177 /// let mut store = Store::<()>::default(); 178 /// 179 /// // Create a manually-rooted `externref` wrapping a `str`. 180 /// let externref = ExternRef::new_manually_rooted(&mut store, "hello!"); 181 /// 182 /// // Use `externref` a bunch... 183 /// 184 /// // Don't forget to explicitly unroot the `externref` when done using it. 185 /// externref.unroot(&mut store); 186 /// # Ok(()) 187 /// # } 188 /// ``` 189 pub fn new_manually_rooted<T>( 190 mut store: impl AsContextMut, 191 value: T, 192 ) -> ManuallyRooted<ExternRef> 193 where 194 T: 'static + Any + Send + Sync, 195 { 196 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 197 198 // Safety: We proviode `VMExternRef`'s invariants via the way that 199 // `ExternRef` methods take `impl AsContext[Mut]` methods. 200 let inner = unsafe { VMExternRef::new(value) }; 201 let inner = unsafe { inner.into_gc_ref() }; 202 203 // Safety: `inner` is a GC reference pointing to an `externref` GC 204 // object. 205 unsafe { ManuallyRooted::new(&mut store, inner) } 206 } 207 208 /// Create an `ExternRef` from an underlying `VMExternRef`. 209 /// 210 /// # Safety 211 /// 212 /// The underlying `VMExternRef` must belong to `store`. 213 pub(crate) unsafe fn from_vm_extern_ref( 214 store: &mut AutoAssertNoGc<'_>, 215 inner: VMExternRef, 216 ) -> Rooted<Self> { 217 // Safety: `inner` is a GC reference pointing to an `externref` GC 218 // object. 219 unsafe { Rooted::new(store, inner.into_gc_ref()) } 220 } 221 222 pub(crate) fn to_vm_extern_ref(&self, store: &mut AutoAssertNoGc<'_>) -> Option<VMExternRef> { 223 let gc_ref = self.inner.get_gc_ref(store)?; 224 // Safety: Our underlying `gc_ref` is always pointing to an `externref`. 225 Some(unsafe { VMExternRef::clone_from_gc_ref(*gc_ref) }) 226 } 227 228 pub(crate) fn try_to_vm_extern_ref( 229 &self, 230 store: &mut AutoAssertNoGc<'_>, 231 ) -> Result<VMExternRef> { 232 self.to_vm_extern_ref(store) 233 .ok_or_else(|| anyhow!("attempted to use an `externref` that was unrooted")) 234 } 235 236 /// Get a shared borrow of the underlying data for this `ExternRef`. 237 /// 238 /// Returns an error if this `externref` GC reference has been unrooted (eg 239 /// if you attempt to use a `Rooted<ExternRef>` after exiting the scope it 240 /// was rooted within). See the documentation for 241 /// [`Rooted<T>`][crate::Rooted] for more details. 242 /// 243 /// # Example 244 /// 245 /// ``` 246 /// # use wasmtime::*; 247 /// # fn _foo() -> Result<()> { 248 /// let mut store = Store::<()>::default(); 249 /// 250 /// let externref = ExternRef::new(&mut store, "hello"); 251 /// 252 /// // Access the `externref`'s host data. 253 /// let data = externref.data(&store)?; 254 /// // Dowcast it to a `&str`. 255 /// let data = data.downcast_ref::<&str>().ok_or_else(|| Error::msg("not a str"))?; 256 /// // We should have got the data we created the `externref` with! 257 /// assert_eq!(*data, "hello"); 258 /// # Ok(()) 259 /// # } 260 /// ``` 261 pub fn data<'a, T>( 262 &self, 263 store: impl Into<StoreContext<'a, T>>, 264 ) -> Result<&'a (dyn Any + Send + Sync)> 265 where 266 T: 'a, 267 { 268 let store = store.into().0; 269 270 // Safety: we don't do anything that could cause a GC while handling 271 // this `gc_ref`. 272 // 273 // NB: We can't use AutoAssertNoGc` here because then the lifetime of 274 // `gc_ref.as_extern_ref()` would only be the lifetime of the `store` 275 // local, rather than `'a`. 276 let gc_ref = unsafe { self.inner.unchecked_try_gc_ref(store)? }; 277 278 let externref = gc_ref.as_extern_ref(); 279 Ok(externref.data()) 280 } 281 282 /// Get an exclusive borrow of the underlying data for this `ExternRef`. 283 /// 284 /// Returns an error if this `externref` GC reference has been unrooted (eg 285 /// if you attempt to use a `Rooted<ExternRef>` after exiting the scope it 286 /// was rooted within). See the documentation for 287 /// [`Rooted<T>`][crate::Rooted] for more details. 288 /// 289 /// # Example 290 /// 291 /// ``` 292 /// # use wasmtime::*; 293 /// # fn _foo() -> Result<()> { 294 /// let mut store = Store::<()>::default(); 295 /// 296 /// let externref = ExternRef::new::<usize>(&mut store, 0); 297 /// 298 /// // Access the `externref`'s host data. 299 /// let data = externref.data_mut(&mut store)?; 300 /// // Dowcast it to a `usize`. 301 /// let data = data.downcast_mut::<usize>().ok_or_else(|| Error::msg("not a usize"))?; 302 /// // We initialized to zero. 303 /// assert_eq!(*data, 0); 304 /// // And we can mutate the value! 305 /// *data += 10; 306 /// # Ok(()) 307 /// # } 308 /// ``` 309 pub fn data_mut<'a, T>( 310 &self, 311 store: impl Into<StoreContextMut<'a, T>>, 312 ) -> Result<&'a mut (dyn Any + Send + Sync)> 313 where 314 T: 'a, 315 { 316 let store = store.into(); 317 318 // Safety: we don't do anything that could cause a GC while handling 319 // this `gc_ref`. 320 // 321 // NB: We can't use AutoAssertNoGc` here because then the lifetime of 322 // `gc_ref.as_extern_ref()` would only be the lifetime of the `store` 323 // local, rather than `'a`. 324 let gc_ref = unsafe { self.inner.unchecked_try_gc_ref_mut(store.0)? }; 325 326 let externref = gc_ref.as_extern_ref_mut(); 327 // Safety: We have a mutable borrow on the store, which prevents 328 // concurrent access to the underlying `VMExternRef`. 329 Ok(unsafe { externref.data_mut() }) 330 } 331 332 /// Creates a new strongly-owned [`ExternRef`] from the raw value provided. 333 /// 334 /// This is intended to be used in conjunction with [`Func::new_unchecked`], 335 /// [`Func::call_unchecked`], and [`ValRaw`] with its `externref` field. 336 /// 337 /// This function assumes that `raw` is an externref value which is 338 /// currently rooted within the [`Store`]. 339 /// 340 /// # Unsafety 341 /// 342 /// This function is particularly `unsafe` because `raw` not only must be a 343 /// valid externref value produced prior by `to_raw` but it must also be 344 /// correctly rooted within the store. When arguments are provided to a 345 /// callback with [`Func::new_unchecked`], for example, or returned via 346 /// [`Func::call_unchecked`], if a GC is performed within the store then 347 /// floating externref values are not rooted and will be GC'd, meaning that 348 /// this function will no longer be safe to call with the values cleaned up. 349 /// This function must be invoked *before* possible GC operations can happen 350 /// (such as calling wasm). 351 /// 352 /// When in doubt try to not use this. Instead use the safe Rust APIs of 353 /// [`TypedFunc`] and friends. 354 /// 355 /// [`Func::call_unchecked`]: crate::Func::call_unchecked 356 /// [`Func::new_unchecked`]: crate::Func::new_unchecked 357 /// [`Store`]: crate::Store 358 /// [`TypedFunc`]: crate::TypedFunc 359 /// [`ValRaw`]: crate::ValRaw 360 pub unsafe fn from_raw( 361 mut store: impl AsContextMut, 362 raw: *mut c_void, 363 ) -> Option<Rooted<ExternRef>> { 364 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 365 let raw = raw.cast::<u8>(); 366 let inner = VMExternRef::clone_from_raw(raw)?; 367 Some(Self::from_vm_extern_ref(&mut store, inner)) 368 } 369 370 /// Converts this [`ExternRef`] to a raw value suitable to store within a 371 /// [`ValRaw`]. 372 /// 373 /// Returns an error if this `externref` has been unrooted. 374 /// 375 /// # Unsafety 376 /// 377 /// Produces a raw value which is only safe to pass into a store if a GC 378 /// doesn't happen between when the value is produce and when it's passed 379 /// into the store. 380 /// 381 /// [`ValRaw`]: crate::ValRaw 382 pub unsafe fn to_raw(&self, mut store: impl AsContextMut) -> Result<*mut c_void> { 383 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 384 let gc_ref = self.inner.try_gc_ref(&store)?; 385 let inner = VMExternRef::clone_from_gc_ref(*gc_ref); 386 let raw = inner.as_raw(); 387 store.insert_vmexternref_without_gc(inner); 388 Ok(raw.cast()) 389 } 390 } 391