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