lucet_runtime_internals/
instance.rs

1pub mod execution;
2mod siginfo_ext;
3pub mod signals;
4pub mod state;
5
6pub use crate::instance::execution::{KillError, KillState, KillSuccess, KillSwitch};
7pub use crate::instance::signals::{signal_handler_none, SignalBehavior, SignalHandler};
8pub use crate::instance::state::State;
9
10use crate::alloc::{Alloc, HOST_PAGE_SIZE_EXPECTED};
11use crate::context::Context;
12use crate::embed_ctx::CtxMap;
13use crate::error::Error;
14use crate::module::{self, FunctionHandle, FunctionPointer, Global, GlobalValue, Module, TrapCode};
15use crate::region::RegionInternal;
16use crate::val::{UntypedRetVal, Val};
17use crate::WASM_PAGE_SIZE;
18use libc::{c_void, pthread_self, siginfo_t, uintptr_t};
19use lucet_module::InstanceRuntimeData;
20use memoffset::offset_of;
21use std::any::Any;
22use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell};
23use std::marker::PhantomData;
24use std::mem;
25use std::ops::{Deref, DerefMut};
26use std::ptr::{self, NonNull};
27use std::sync::Arc;
28
29pub const LUCET_INSTANCE_MAGIC: u64 = 746_932_922;
30
31thread_local! {
32    /// The host context.
33    ///
34    /// Control returns here implicitly due to the setup in `Context::init()` when guest functions
35    /// return normally. Control can return here explicitly from signal handlers when the guest
36    /// program needs to be terminated.
37    ///
38    /// This is an `UnsafeCell` due to nested borrows. The context must be borrowed mutably when
39    /// swapping to the guest context, which means that borrow exists for the entire time the guest
40    /// function runs even though the mutation to the host context is done only at the beginning of
41    /// the swap. Meanwhile, the signal handler can run at any point during the guest function, and
42    /// so it also must be able to immutably borrow the host context if it needs to swap back. The
43    /// runtime borrowing constraints for a `RefCell` are therefore too strict for this variable.
44    pub(crate) static HOST_CTX: UnsafeCell<Context> = UnsafeCell::new(Context::new());
45
46    /// The currently-running `Instance`, if one exists.
47    pub(crate) static CURRENT_INSTANCE: RefCell<Option<NonNull<Instance>>> = RefCell::new(None);
48}
49
50/// A smart pointer to an [`Instance`](struct.Instance.html) that properly manages cleanup when dropped.
51///
52/// Instances are always stored in memory backed by a `Region`; we never want to create one directly
53/// with the Rust allocator. This type allows us to abide by that rule while also having an owned
54/// type that cleans up the instance when we are done with it.
55///
56/// Since this type implements `Deref` and `DerefMut` to `Instance`, it can usually be treated as
57/// though it were a `&mut Instance`.
58pub struct InstanceHandle {
59    inst: NonNull<Instance>,
60    needs_inst_drop: bool,
61}
62
63// raw pointer lint
64unsafe impl Send for InstanceHandle {}
65
66/// Create a new `InstanceHandle`.
67///
68/// This is not meant for public consumption, but rather is used to make implementations of
69/// `Region`.
70///
71/// # Safety
72///
73/// This function runs the guest code for the WebAssembly `start` section, and running any guest
74/// code is potentially unsafe; see [`Instance::run()`](struct.Instance.html#method.run).
75pub fn new_instance_handle(
76    instance: *mut Instance,
77    module: Arc<dyn Module>,
78    alloc: Alloc,
79    embed_ctx: CtxMap,
80) -> Result<InstanceHandle, Error> {
81    let inst = NonNull::new(instance)
82        .ok_or_else(|| lucet_format_err!("instance pointer is null; this is a bug"))?;
83
84    lucet_ensure!(
85        unsafe { inst.as_ref().magic } != LUCET_INSTANCE_MAGIC,
86        "created a new instance handle in memory with existing instance magic; this is a bug"
87    );
88
89    let mut handle = InstanceHandle {
90        inst,
91        needs_inst_drop: false,
92    };
93
94    let inst = Instance::new(alloc, module, embed_ctx);
95
96    unsafe {
97        // this is wildly unsafe! you must be very careful to not let the drop impls run on the
98        // uninitialized fields; see
99        // <https://doc.rust-lang.org/std/mem/fn.forget.html#use-case-1>
100
101        // write the whole struct into place over the uninitialized page
102        ptr::write(&mut *handle, inst);
103    };
104
105    handle.needs_inst_drop = true;
106
107    handle.reset()?;
108
109    Ok(handle)
110}
111
112pub fn instance_handle_to_raw(mut inst: InstanceHandle) -> *mut Instance {
113    inst.needs_inst_drop = false;
114    inst.inst.as_ptr()
115}
116
117pub unsafe fn instance_handle_from_raw(
118    ptr: *mut Instance,
119    needs_inst_drop: bool,
120) -> InstanceHandle {
121    InstanceHandle {
122        inst: NonNull::new_unchecked(ptr),
123        needs_inst_drop,
124    }
125}
126
127// Safety argument for these deref impls: the instance's `Alloc` field contains an `Arc` to the
128// region that backs this memory, keeping the page containing the `Instance` alive as long as the
129// region exists
130
131impl Deref for InstanceHandle {
132    type Target = Instance;
133    fn deref(&self) -> &Self::Target {
134        unsafe { self.inst.as_ref() }
135    }
136}
137
138impl DerefMut for InstanceHandle {
139    fn deref_mut(&mut self) -> &mut Self::Target {
140        unsafe { self.inst.as_mut() }
141    }
142}
143
144impl Drop for InstanceHandle {
145    fn drop(&mut self) {
146        if self.needs_inst_drop {
147            unsafe {
148                let inst = self.inst.as_mut();
149
150                // Grab a handle to the region to ensure it outlives `inst`.
151                //
152                // This ensures that the region won't be dropped by `inst` being
153                // dropped, which could result in `inst` being unmapped by the
154                // Region *during* drop of the Instance's fields.
155                let region: Arc<dyn RegionInternal> = inst.alloc().region.clone();
156
157                // drop the actual instance
158                std::ptr::drop_in_place(inst);
159
160                // and now we can drop what may be the last Arc<Region>. If it is
161                // it can safely do what it needs with memory; we're not running
162                // destructors on it anymore.
163                mem::drop(region);
164            }
165        }
166    }
167}
168
169/// A Lucet program, together with its dedicated memory and signal handlers.
170///
171/// This is the primary interface for running programs, examining return values, and accessing the
172/// WebAssembly heap.
173///
174/// `Instance`s are never created by runtime users directly, but rather are acquired from
175/// [`Region`](../region/trait.Region.html)s and often accessed through
176/// [`InstanceHandle`](../instance/struct.InstanceHandle.html) smart pointers. This guarantees that instances
177/// and their fields are never moved in memory, otherwise raw pointers in the metadata could be
178/// unsafely invalidated.
179///
180/// An instance occupies one 4096-byte page in memory, with a layout like:
181/// ```text
182/// 0xXXXXX000:
183///   Instance {
184///     .magic
185///     .embed_ctx
186///      ... etc ...
187///   }
188///
189///   // unused space
190///
191///   InstanceInternals {
192///     .globals
193///     .instruction_counter
194///   } // last address *inside* `InstanceInternals` is 0xXXXXXFFF
195/// 0xXXXXY000: // start of next page, VMContext points here
196///   Heap {
197///     ..
198///   }
199/// ```
200///
201/// This layout allows modules to tightly couple to a handful of fields related to the instance,
202/// rather than possibly requiring compiler-side changes (and recompiles) whenever `Instance`
203/// changes.
204///
205/// It also obligates `Instance` to be immediately followed by the heap, but otherwise leaves the
206/// locations of the stack, globals, and any other data, to be implementation-defined by the
207/// `Region` that actually creates `Slot`s onto which `Instance` are mapped.
208/// For information about the layout of all instance-related memory, see the documentation of
209/// [MmapRegion](../region/mmap/struct.MmapRegion.html).
210#[repr(C)]
211#[repr(align(4096))]
212pub struct Instance {
213    /// Used to catch bugs in pointer math used to find the address of the instance
214    magic: u64,
215
216    /// The embedding context is a map containing embedder-specific values that are used to
217    /// implement hostcalls
218    pub(crate) embed_ctx: CtxMap,
219
220    /// The program (WebAssembly module) that is the entrypoint for the instance.
221    module: Arc<dyn Module>,
222
223    /// The `Context` in which the guest program runs
224    pub(crate) ctx: Context,
225
226    /// Instance state and error information
227    pub(crate) state: State,
228
229    /// Small mutexed state used for remote kill switch functionality
230    pub(crate) kill_state: Arc<KillState>,
231
232    /// The memory allocated for this instance
233    alloc: Alloc,
234
235    /// Handler run for signals that do not arise from a known WebAssembly trap, or that involve
236    /// memory outside of the current instance.
237    fatal_handler: fn(&Instance) -> !,
238
239    /// A fatal handler set from C
240    c_fatal_handler: Option<unsafe extern "C" fn(*mut Instance)>,
241
242    /// Handler run when `SIGBUS`, `SIGFPE`, `SIGILL`, or `SIGSEGV` are caught by the instance thread.
243    signal_handler: Box<
244        dyn Fn(
245            &Instance,
246            &Option<TrapCode>,
247            libc::c_int,
248            *const siginfo_t,
249            *const c_void,
250        ) -> SignalBehavior,
251    >,
252
253    /// Pointer to the function used as the entrypoint (for use in backtraces)
254    entrypoint: Option<FunctionPointer>,
255
256    /// The value passed back to the guest when resuming a yielded instance.
257    pub(crate) resumed_val: Option<Box<dyn Any + 'static>>,
258
259    /// `_padding` must be the last member of the structure.
260    /// This marks where the padding starts to make the structure exactly 4096 bytes long.
261    /// It is also used to compute the size of the structure up to that point, i.e. without padding.
262    _padding: (),
263}
264
265/// Users of `Instance` must be very careful about when instances are dropped!
266///
267/// Typically you will not have to worry about this, as InstanceHandle will robustly handle
268/// Instance drop semantics. If an instance is dropped, and the Region it's in has already dropped,
269/// it may contain the last reference counted pointer to its Region. If so, when Instance's
270/// destructor runs, Region will be dropped, and may free or otherwise invalidate the memory that
271/// this Instance exists in, *while* the Instance destructor is executing.
272impl Drop for Instance {
273    fn drop(&mut self) {
274        // Reset magic to indicate this instance
275        // is no longer valid
276        self.magic = 0;
277    }
278}
279
280/// The result of running or resuming an [`Instance`](struct.Instance.html).
281#[derive(Debug)]
282pub enum RunResult {
283    /// An instance returned with a value.
284    ///
285    /// The actual type of the contained value depends on the return type of the guest function that
286    /// was called. For guest functions with no return value, it is undefined behavior to do
287    /// anything with this value.
288    Returned(UntypedRetVal),
289    /// An instance yielded, potentially with a value.
290    ///
291    /// This arises when a hostcall invokes one of the
292    /// [`Vmctx::yield_*()`](vmctx/struct.Vmctx.html#method.yield_) family of methods. Depending on which
293    /// variant is used, the `YieldedVal` may contain a value passed from the guest context to the
294    /// host.
295    ///
296    /// An instance that has yielded may only be resumed
297    /// ([with](struct.Instance.html#method.resume_with_val) or
298    /// [without](struct.Instance.html#method.resume) a value to returned to the guest),
299    /// [reset](struct.Instance.html#method.reset), or dropped. Attempting to run an instance from a
300    /// new entrypoint after it has yielded but without first resetting will result in an error.
301    Yielded(YieldedVal),
302}
303
304impl RunResult {
305    /// Try to get a return value from a run result, returning `Error::InstanceNotReturned` if the
306    /// instance instead yielded.
307    pub fn returned(self) -> Result<UntypedRetVal, Error> {
308        match self {
309            RunResult::Returned(rv) => Ok(rv),
310            RunResult::Yielded(_) => Err(Error::InstanceNotReturned),
311        }
312    }
313
314    /// Try to get a reference to a return value from a run result, returning
315    /// `Error::InstanceNotReturned` if the instance instead yielded.
316    pub fn returned_ref(&self) -> Result<&UntypedRetVal, Error> {
317        match self {
318            RunResult::Returned(rv) => Ok(rv),
319            RunResult::Yielded(_) => Err(Error::InstanceNotReturned),
320        }
321    }
322
323    /// Returns `true` if the instance returned a value.
324    pub fn is_returned(&self) -> bool {
325        self.returned_ref().is_ok()
326    }
327
328    /// Unwraps a run result into a return value.
329    ///
330    /// # Panics
331    ///
332    /// Panics if the instance instead yielded, with a panic message including the passed message.
333    pub fn expect_returned(self, msg: &str) -> UntypedRetVal {
334        self.returned().expect(msg)
335    }
336
337    /// Unwraps a run result into a returned value.
338    ///
339    /// # Panics
340    ///
341    /// Panics if the instance instead yielded.
342    pub fn unwrap_returned(self) -> UntypedRetVal {
343        self.returned().unwrap()
344    }
345
346    /// Try to get a yielded value from a run result, returning `Error::InstanceNotYielded` if the
347    /// instance instead returned.
348    pub fn yielded(self) -> Result<YieldedVal, Error> {
349        match self {
350            RunResult::Returned(_) => Err(Error::InstanceNotYielded),
351            RunResult::Yielded(yv) => Ok(yv),
352        }
353    }
354
355    /// Try to get a reference to a yielded value from a run result, returning
356    /// `Error::InstanceNotYielded` if the instance instead returned.
357    pub fn yielded_ref(&self) -> Result<&YieldedVal, Error> {
358        match self {
359            RunResult::Returned(_) => Err(Error::InstanceNotYielded),
360            RunResult::Yielded(yv) => Ok(yv),
361        }
362    }
363
364    /// Returns `true` if the instance yielded.
365    pub fn is_yielded(&self) -> bool {
366        self.yielded_ref().is_ok()
367    }
368
369    /// Unwraps a run result into a yielded value.
370    ///
371    /// # Panics
372    ///
373    /// Panics if the instance instead returned, with a panic message including the passed message.
374    pub fn expect_yielded(self, msg: &str) -> YieldedVal {
375        self.yielded().expect(msg)
376    }
377
378    /// Unwraps a run result into a yielded value.
379    ///
380    /// # Panics
381    ///
382    /// Panics if the instance instead returned.
383    pub fn unwrap_yielded(self) -> YieldedVal {
384        self.yielded().unwrap()
385    }
386}
387
388/// APIs that are internal, but useful to implementors of extension modules; you probably don't want
389/// this trait!
390///
391/// This is a trait rather than inherent `impl`s in order to keep the `lucet-runtime` API clean and
392/// safe.
393pub trait InstanceInternal {
394    fn alloc(&self) -> &Alloc;
395    fn alloc_mut(&mut self) -> &mut Alloc;
396    fn module(&self) -> &dyn Module;
397    fn state(&self) -> &State;
398    fn valid_magic(&self) -> bool;
399}
400
401impl InstanceInternal for Instance {
402    /// Get a reference to the instance's `Alloc`.
403    fn alloc(&self) -> &Alloc {
404        &self.alloc
405    }
406
407    /// Get a mutable reference to the instance's `Alloc`.
408    fn alloc_mut(&mut self) -> &mut Alloc {
409        &mut self.alloc
410    }
411
412    /// Get a reference to the instance's `Module`.
413    fn module(&self) -> &dyn Module {
414        self.module.deref()
415    }
416
417    /// Get a reference to the instance's `State`.
418    fn state(&self) -> &State {
419        &self.state
420    }
421
422    /// Check whether the instance magic is valid.
423    fn valid_magic(&self) -> bool {
424        self.magic == LUCET_INSTANCE_MAGIC
425    }
426}
427
428// Public API
429impl Instance {
430    /// Run a function with arguments in the guest context at the given entrypoint.
431    ///
432    /// ```no_run
433    /// # use lucet_runtime_internals::instance::InstanceHandle;
434    /// # let instance: InstanceHandle = unimplemented!();
435    /// // regular execution yields `Ok(UntypedRetVal)`
436    /// let retval = instance.run("factorial", &[5u64.into()]).unwrap().unwrap_returned();
437    /// assert_eq!(u64::from(retval), 120u64);
438    ///
439    /// // runtime faults yield `Err(Error)`
440    /// let result = instance.run("faulting_function", &[]);
441    /// assert!(result.is_err());
442    /// ```
443    ///
444    /// # Safety
445    ///
446    /// This is unsafe in two ways:
447    ///
448    /// - The type of the entrypoint might not be correct. It might take a different number or
449    /// different types of arguments than are provided to `args`. It might not even point to a
450    /// function! We will likely add type information to `lucetc` output so we can dynamically check
451    /// the type in the future.
452    ///
453    /// - The entrypoint is foreign code. While we may be convinced that WebAssembly compiled to
454    /// native code by `lucetc` is safe, we do not have the same guarantee for the hostcalls that a
455    /// guest may invoke. They might be implemented in an unsafe language, so we must treat this
456    /// call as unsafe, just like any other FFI call.
457    ///
458    /// For the moment, we do not mark this as `unsafe` in the Rust type system, but that may change
459    /// in the future.
460    pub fn run(&mut self, entrypoint: &str, args: &[Val]) -> Result<RunResult, Error> {
461        let func = self.module.get_export_func(entrypoint)?;
462        self.run_func(func, &args)
463    }
464
465    /// Run a function with arguments in the guest context from the [WebAssembly function
466    /// table](https://webassembly.github.io/spec/core/syntax/modules.html#tables).
467    ///
468    /// # Safety
469    ///
470    /// The same safety caveats of [`Instance::run()`](struct.Instance.html#method.run) apply.
471    pub fn run_func_idx(
472        &mut self,
473        table_idx: u32,
474        func_idx: u32,
475        args: &[Val],
476    ) -> Result<RunResult, Error> {
477        let func = self.module.get_func_from_idx(table_idx, func_idx)?;
478        self.run_func(func, &args)
479    }
480
481    /// Resume execution of an instance that has yielded without providing a value to the guest.
482    ///
483    /// This should only be used when the guest yielded with
484    /// [`Vmctx::yield_()`](vmctx/struct.Vmctx.html#method.yield_) or
485    /// [`Vmctx::yield_val()`](vmctx/struct.Vmctx.html#method.yield_val). Otherwise, this call will
486    /// fail with `Error::InvalidArgument`.
487    ///
488    /// # Safety
489    ///
490    /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run)
491    /// applies.
492    pub fn resume(&mut self) -> Result<RunResult, Error> {
493        self.resume_with_val(EmptyYieldVal)
494    }
495
496    /// Resume execution of an instance that has yielded, providing a value to the guest.
497    ///
498    /// The type of the provided value must match the type expected by
499    /// [`Vmctx::yield_expecting_val()`](vmctx/struct.Vmctx.html#method.yield_expecting_val) or
500    /// [`Vmctx::yield_val_expecting_val()`](vmctx/struct.Vmctx.html#method.yield_val_expecting_val).
501    ///
502    /// The provided value will be dynamically typechecked against the type the guest expects to
503    /// receive, and if that check fails, this call will fail with `Error::InvalidArgument`.
504    ///
505    /// # Safety
506    ///
507    /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run)
508    /// applies.
509    pub fn resume_with_val<A: Any + 'static>(&mut self, val: A) -> Result<RunResult, Error> {
510        match &self.state {
511            State::Yielded { expecting, .. } => {
512                // make sure the resumed value is of the right type
513                if !expecting.is::<PhantomData<A>>() {
514                    return Err(Error::InvalidArgument(
515                        "type mismatch between yielded instance expected value and resumed value",
516                    ));
517                }
518            }
519            _ => return Err(Error::InvalidArgument("can only resume a yielded instance")),
520        }
521
522        self.resumed_val = Some(Box::new(val) as Box<dyn Any + 'static>);
523
524        self.swap_and_return()
525    }
526
527    /// Reset the instance's heap and global variables to their initial state.
528    ///
529    /// The WebAssembly `start` section will also be run, if one exists.
530    ///
531    /// The embedder contexts present at instance creation or added with
532    /// [`Instance::insert_embed_ctx()`](struct.Instance.html#method.insert_embed_ctx) are not
533    /// modified by this call; it is the embedder's responsibility to clear or reset their state if
534    /// necessary.
535    ///
536    /// # Safety
537    ///
538    /// This function runs the guest code for the WebAssembly `start` section, and running any guest
539    /// code is potentially unsafe; see [`Instance::run()`](struct.Instance.html#method.run).
540    pub fn reset(&mut self) -> Result<(), Error> {
541        self.alloc.reset_heap(self.module.as_ref())?;
542        let globals = unsafe { self.alloc.globals_mut() };
543        let mod_globals = self.module.globals();
544        for (i, v) in mod_globals.iter().enumerate() {
545            globals[i] = match v.global() {
546                Global::Import { .. } => {
547                    return Err(Error::Unsupported(format!(
548                        "global imports are unsupported; found: {:?}",
549                        v
550                    )));
551                }
552                Global::Def(def) => def.init_val(),
553            };
554        }
555
556        self.state = State::Ready;
557
558        self.run_start()?;
559
560        Ok(())
561    }
562
563    /// Grow the guest memory by the given number of WebAssembly pages.
564    ///
565    /// On success, returns the number of pages that existed before the call.
566    pub fn grow_memory(&mut self, additional_pages: u32) -> Result<u32, Error> {
567        let additional_bytes = additional_pages
568            .checked_mul(WASM_PAGE_SIZE)
569            .ok_or_else(|| lucet_format_err!("additional pages larger than wasm address space",))?;
570        let orig_len = self
571            .alloc
572            .expand_heap(additional_bytes, self.module.as_ref())?;
573        Ok(orig_len / WASM_PAGE_SIZE)
574    }
575
576    /// Return the WebAssembly heap as a slice of bytes.
577    pub fn heap(&self) -> &[u8] {
578        unsafe { self.alloc.heap() }
579    }
580
581    /// Return the WebAssembly heap as a mutable slice of bytes.
582    pub fn heap_mut(&mut self) -> &mut [u8] {
583        unsafe { self.alloc.heap_mut() }
584    }
585
586    /// Return the WebAssembly heap as a slice of `u32`s.
587    pub fn heap_u32(&self) -> &[u32] {
588        unsafe { self.alloc.heap_u32() }
589    }
590
591    /// Return the WebAssembly heap as a mutable slice of `u32`s.
592    pub fn heap_u32_mut(&mut self) -> &mut [u32] {
593        unsafe { self.alloc.heap_u32_mut() }
594    }
595
596    /// Return the WebAssembly globals as a slice of `i64`s.
597    pub fn globals(&self) -> &[GlobalValue] {
598        unsafe { self.alloc.globals() }
599    }
600
601    /// Return the WebAssembly globals as a mutable slice of `i64`s.
602    pub fn globals_mut(&mut self) -> &mut [GlobalValue] {
603        unsafe { self.alloc.globals_mut() }
604    }
605
606    /// Check whether a given range in the host address space overlaps with the memory that backs
607    /// the instance heap.
608    pub fn check_heap<T>(&self, ptr: *const T, len: usize) -> bool {
609        self.alloc.mem_in_heap(ptr, len)
610    }
611
612    /// Check whether a context value of a particular type exists.
613    pub fn contains_embed_ctx<T: Any>(&self) -> bool {
614        self.embed_ctx.contains::<T>()
615    }
616
617    /// Get a reference to a context value of a particular type, if it exists.
618    pub fn get_embed_ctx<T: Any>(&self) -> Option<Result<Ref<'_, T>, BorrowError>> {
619        self.embed_ctx.try_get::<T>()
620    }
621
622    /// Get a mutable reference to a context value of a particular type, if it exists.
623    pub fn get_embed_ctx_mut<T: Any>(&self) -> Option<Result<RefMut<'_, T>, BorrowMutError>> {
624        self.embed_ctx.try_get_mut::<T>()
625    }
626
627    /// Insert a context value.
628    ///
629    /// If a context value of the same type already existed, it is returned.
630    ///
631    /// **Note**: this method is intended for embedder contexts that need to be added _after_ an
632    /// instance is created and initialized. To add a context for an instance's entire lifetime,
633    /// including the execution of its `start` section, see
634    /// [`Region::new_instance_builder()`](trait.Region.html#method.new_instance_builder).
635    pub fn insert_embed_ctx<T: Any>(&mut self, x: T) -> Option<T> {
636        self.embed_ctx.insert(x)
637    }
638
639    /// Remove a context value of a particular type, returning it if it exists.
640    pub fn remove_embed_ctx<T: Any>(&mut self) -> Option<T> {
641        self.embed_ctx.remove::<T>()
642    }
643
644    /// Set the handler run when `SIGBUS`, `SIGFPE`, `SIGILL`, or `SIGSEGV` are caught by the
645    /// instance thread.
646    ///
647    /// In most cases, these signals are unrecoverable for the instance that raised them, but do not
648    /// affect the rest of the process.
649    ///
650    /// The default signal handler returns
651    /// [`SignalBehavior::Default`](enum.SignalBehavior.html#variant.Default), which yields a
652    /// runtime fault error.
653    ///
654    /// The signal handler must be
655    /// [signal-safe](http://man7.org/linux/man-pages/man7/signal-safety.7.html).
656    pub fn set_signal_handler<H>(&mut self, handler: H)
657    where
658        H: 'static
659            + Fn(
660                &Instance,
661                &Option<TrapCode>,
662                libc::c_int,
663                *const siginfo_t,
664                *const c_void,
665            ) -> SignalBehavior,
666    {
667        self.signal_handler = Box::new(handler) as Box<SignalHandler>;
668    }
669
670    /// Set the handler run for signals that do not arise from a known WebAssembly trap, or that
671    /// involve memory outside of the current instance.
672    ///
673    /// Fatal signals are not only unrecoverable for the instance that raised them, but may
674    /// compromise the correctness of the rest of the process if unhandled.
675    ///
676    /// The default fatal handler calls `panic!()`.
677    pub fn set_fatal_handler(&mut self, handler: fn(&Instance) -> !) {
678        self.fatal_handler = handler;
679    }
680
681    /// Set the fatal handler to a C-compatible function.
682    ///
683    /// This is a separate interface, because C functions can't return the `!` type. Like the
684    /// regular `fatal_handler`, it is not expected to return, but we cannot enforce that through
685    /// types.
686    ///
687    /// When a fatal error occurs, this handler is run first, and then the regular `fatal_handler`
688    /// runs in case it returns.
689    pub fn set_c_fatal_handler(&mut self, handler: unsafe extern "C" fn(*mut Instance)) {
690        self.c_fatal_handler = Some(handler);
691    }
692
693    pub fn kill_switch(&self) -> KillSwitch {
694        KillSwitch::new(Arc::downgrade(&self.kill_state))
695    }
696
697    pub fn is_ready(&self) -> bool {
698        self.state.is_ready()
699    }
700
701    pub fn is_yielded(&self) -> bool {
702        self.state.is_yielded()
703    }
704
705    pub fn is_faulted(&self) -> bool {
706        self.state.is_faulted()
707    }
708
709    pub fn is_terminated(&self) -> bool {
710        self.state.is_terminated()
711    }
712
713    // This needs to be public as it's used in the expansion of `lucet_hostcalls`, available for
714    // external use. But you *really* shouldn't have to call this yourself, so we're going to keep
715    // it out of rustdoc.
716    #[doc(hidden)]
717    pub fn uninterruptable<T, F: FnOnce() -> T>(&mut self, f: F) -> T {
718        self.kill_state.begin_hostcall();
719        let res = f();
720        let stop_reason = self.kill_state.end_hostcall();
721
722        if let Some(termination_details) = stop_reason {
723            // TODO: once we have unwinding, panic here instead so we unwind host frames
724            unsafe {
725                self.terminate(termination_details);
726            }
727        }
728
729        res
730    }
731
732    #[inline]
733    pub fn get_instruction_count(&self) -> Option<u64> {
734        if self.module.is_instruction_count_instrumented() {
735            return Some(self.get_instance_implicits().instruction_count);
736        }
737        None
738    }
739
740    #[inline]
741    pub fn set_instruction_count(&mut self, instruction_count: u64) {
742        self.get_instance_implicits_mut().instruction_count = instruction_count;
743    }
744}
745
746// Private API
747impl Instance {
748    fn new(alloc: Alloc, module: Arc<dyn Module>, embed_ctx: CtxMap) -> Self {
749        let globals_ptr = alloc.slot().globals as *mut i64;
750
751        let mut inst = Instance {
752            magic: LUCET_INSTANCE_MAGIC,
753            embed_ctx,
754            module,
755            ctx: Context::new(),
756            state: State::Ready,
757            kill_state: Arc::new(KillState::new()),
758            alloc,
759            fatal_handler: default_fatal_handler,
760            c_fatal_handler: None,
761            signal_handler: Box::new(signal_handler_none) as Box<SignalHandler>,
762            entrypoint: None,
763            resumed_val: None,
764            _padding: (),
765        };
766        inst.set_globals_ptr(globals_ptr);
767        inst.set_instruction_count(0);
768
769        assert_eq!(mem::size_of::<Instance>(), HOST_PAGE_SIZE_EXPECTED);
770        let unpadded_size = offset_of!(Instance, _padding);
771        assert!(unpadded_size <= HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>());
772        inst
773    }
774
775    // The globals pointer must be stored right before the end of the structure, padded to the page size,
776    // so that it is 8 bytes before the heap.
777    // For this reason, the alignment of the structure is set to 4096, and we define accessors that
778    // read/write the globals pointer as bytes [4096-8..4096] of that structure represented as raw bytes.
779    // InstanceRuntimeData is placed such that it ends at the end of the page this `Instance` starts
780    // on. So we can access it by *self + PAGE_SIZE - size_of::<InstanceRuntimeData>
781    #[inline]
782    fn get_instance_implicits(&self) -> &InstanceRuntimeData {
783        unsafe {
784            let implicits_ptr = (self as *const _ as *const u8)
785                .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<InstanceRuntimeData>()) as isize)
786                as *const InstanceRuntimeData;
787            mem::transmute::<*const InstanceRuntimeData, &InstanceRuntimeData>(implicits_ptr)
788        }
789    }
790
791    #[inline]
792    fn get_instance_implicits_mut(&mut self) -> &mut InstanceRuntimeData {
793        unsafe {
794            let implicits_ptr = (self as *mut _ as *mut u8)
795                .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<InstanceRuntimeData>()) as isize)
796                as *mut InstanceRuntimeData;
797            mem::transmute::<*mut InstanceRuntimeData, &mut InstanceRuntimeData>(implicits_ptr)
798        }
799    }
800
801    #[allow(dead_code)]
802    #[inline]
803    fn get_globals_ptr(&self) -> *mut i64 {
804        self.get_instance_implicits().globals_ptr
805    }
806
807    #[inline]
808    fn set_globals_ptr(&mut self, globals_ptr: *mut i64) {
809        self.get_instance_implicits_mut().globals_ptr = globals_ptr
810    }
811
812    /// Run a function in guest context at the given entrypoint.
813    fn run_func(&mut self, func: FunctionHandle, args: &[Val]) -> Result<RunResult, Error> {
814        if !(self.state.is_ready() || (self.state.is_faulted() && !self.state.is_fatal())) {
815            return Err(Error::InvalidArgument(
816                "instance must be ready or non-fatally faulted",
817            ));
818        }
819        if func.ptr.as_usize() == 0 {
820            return Err(Error::InvalidArgument(
821                "entrypoint function cannot be null; this is probably a malformed module",
822            ));
823        }
824
825        let sig = self.module.get_signature(func.id);
826
827        // in typechecking these values, we can only really check that arguments are correct.
828        // in the future we might want to make return value use more type safe as well.
829
830        if sig.params.len() != args.len() {
831            return Err(Error::InvalidArgument(
832                "entrypoint function signature mismatch (number of arguments is incorrect)",
833            ));
834        }
835
836        for (param_ty, arg) in sig.params.iter().zip(args.iter()) {
837            if param_ty != &arg.value_type() {
838                return Err(Error::InvalidArgument(
839                    "entrypoint function signature mismatch",
840                ));
841            }
842        }
843
844        self.entrypoint = Some(func.ptr);
845
846        let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)];
847        args_with_vmctx.extend_from_slice(args);
848
849        let self_ptr = self as *mut _;
850        Context::init_with_callback(
851            unsafe { self.alloc.stack_u64_mut() },
852            &mut self.ctx,
853            execution::exit_guest_region,
854            self_ptr,
855            func.ptr.as_usize(),
856            &args_with_vmctx,
857        )?;
858
859        // Set up the guest to set itself as terminable, then continue to
860        // whatever guest code we want to run.
861        //
862        // `lucet_context_activate` takes two arguments:
863        // rsi: address of guest code to execute
864        // rdi: pointer to a bool that indicates the guest can be terminated
865        //
866        // The appropriate value for `rsi` is the top of the guest stack, which
867        // we would otherwise return to and start executing immediately. For
868        // `rdi`, we want to pass a pointer to the instance's `terminable` flag.
869        //
870        // once we've set up arguments, swap out the guest return address with
871        // `lucet_context_activate` so we start execution there.
872        unsafe {
873            let top_of_stack = self.ctx.gpr.rsp as *mut u64;
874            // move the guest code address to rsi
875            self.ctx.gpr.rsi = *top_of_stack;
876            // replace it with the activation thunk
877            *top_of_stack = crate::context::lucet_context_activate as u64;
878            // and store a pointer to indicate we're active
879            self.ctx.gpr.rdi = self.kill_state.terminable_ptr() as u64;
880        }
881
882        self.swap_and_return()
883    }
884
885    /// The core routine for context switching into a guest, and extracting a result.
886    ///
887    /// This must only be called for an instance in a ready, non-fatally faulted, or yielded
888    /// state. The public wrappers around this function should make sure the state is appropriate.
889    fn swap_and_return(&mut self) -> Result<RunResult, Error> {
890        debug_assert!(
891            self.state.is_ready()
892                || (self.state.is_faulted() && !self.state.is_fatal())
893                || self.state.is_yielded()
894        );
895        self.state = State::Running;
896
897        self.kill_state.schedule(unsafe { pthread_self() });
898
899        // there should never be another instance running on this thread when we enter this function
900        CURRENT_INSTANCE.with(|current_instance| {
901            let mut current_instance = current_instance.borrow_mut();
902            assert!(
903                current_instance.is_none(),
904                "no other instance is running on this thread"
905            );
906            // safety: `self` is not null if we are in this function
907            *current_instance = Some(unsafe { NonNull::new_unchecked(self) });
908        });
909
910        self.with_signals_on(|i| {
911            HOST_CTX.with(|host_ctx| {
912                // Save the current context into `host_ctx`, and jump to the guest context. The
913                // lucet context is linked to host_ctx, so it will return here after it finishes,
914                // successfully or otherwise.
915                unsafe { Context::swap(&mut *host_ctx.get(), &mut i.ctx) };
916                Ok(())
917            })
918        })?;
919
920        CURRENT_INSTANCE.with(|current_instance| {
921            *current_instance.borrow_mut() = None;
922        });
923
924        // Sandbox has jumped back to the host process, indicating it has either:
925        //
926        // * returned: state should be `Running`; transition to `Ready` and return a RunResult
927        // * yielded: state should be `Yielding`; transition to `Yielded` and return a RunResult
928        // * trapped: state should be `Faulted`; populate details and return an error or call a handler as appropriate
929        // * terminated: state should be `Terminating`; transition to `Terminated` and return the termination details as an Err
930        //
931        // The state should never be `Ready`, `Terminated`, `Yielded`, or `Transitioning` at this point
932
933        self.kill_state.deschedule();
934
935        // Set transitioning state temporarily so that we can move values out of the current state
936        let st = mem::replace(&mut self.state, State::Transitioning);
937
938        match st {
939            State::Running => {
940                let retval = self.ctx.get_untyped_retval();
941                self.state = State::Ready;
942                Ok(RunResult::Returned(retval))
943            }
944            State::Terminating { details, .. } => {
945                self.state = State::Terminated;
946                Err(Error::RuntimeTerminated(details))
947            }
948            State::Yielding { val, expecting } => {
949                self.state = State::Yielded { expecting };
950                Ok(RunResult::Yielded(val))
951            }
952            State::Faulted {
953                mut details,
954                siginfo,
955                context,
956            } => {
957                // Sandbox is no longer runnable. It's unsafe to determine all error details in the signal
958                // handler, so we fill in extra details here.
959                //
960                // FIXME after lucet-module is complete it should be possible to fill this in without
961                // consulting the process symbol table
962                details.rip_addr_details = self
963                    .module
964                    .addr_details(details.rip_addr as *const c_void)?;
965
966                // fill the state back in with the updated details in case fatal handlers need it
967                self.state = State::Faulted {
968                    details: details.clone(),
969                    siginfo,
970                    context,
971                };
972
973                if details.fatal {
974                    // Some errors indicate that the guest is not functioning correctly or that
975                    // the loaded code violated some assumption, so bail out via the fatal
976                    // handler.
977
978                    // Run the C-style fatal handler, if it exists.
979                    if let Some(h) = self.c_fatal_handler {
980                        unsafe { h(self as *mut Instance) }
981                    }
982
983                    // If there is no C-style fatal handler, or if it (erroneously) returns,
984                    // call the Rust handler that we know will not return
985                    (self.fatal_handler)(self)
986                } else {
987                    // leave the full fault details in the instance state, and return the
988                    // higher-level info to the user
989                    Err(Error::RuntimeFault(details))
990                }
991            }
992            State::Ready | State::Terminated | State::Yielded { .. } | State::Transitioning => Err(
993                lucet_format_err!("\"impossible\" state found in `swap_and_return()`: {}", st),
994            ),
995        }
996    }
997
998    fn run_start(&mut self) -> Result<(), Error> {
999        if let Some(start) = self.module.get_start_func()? {
1000            let res = self.run_func(start, &[])?;
1001            if res.is_yielded() {
1002                return Err(Error::StartYielded);
1003            }
1004        }
1005        Ok(())
1006    }
1007}
1008
1009/// Information about a runtime fault.
1010///
1011/// Runtime faults are raised implictly by signal handlers that return `SignalBehavior::Default` in
1012/// response to signals arising while a guest is running.
1013#[derive(Clone, Debug)]
1014pub struct FaultDetails {
1015    /// If true, the instance's `fatal_handler` will be called.
1016    pub fatal: bool,
1017    /// Information about the type of fault that occurred.
1018    pub trapcode: Option<TrapCode>,
1019    /// The instruction pointer where the fault occurred.
1020    pub rip_addr: uintptr_t,
1021    /// Extra information about the instruction pointer's location, if available.
1022    pub rip_addr_details: Option<module::AddrDetails>,
1023}
1024
1025impl std::fmt::Display for FaultDetails {
1026    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1027        if self.fatal {
1028            write!(f, "fault FATAL ")?;
1029        } else {
1030            write!(f, "fault ")?;
1031        }
1032
1033        if let Some(trapcode) = self.trapcode {
1034            write!(f, "{:?} ", trapcode)?;
1035        } else {
1036            write!(f, "TrapCode::UNKNOWN ")?;
1037        }
1038
1039        write!(f, "code at address {:p}", self.rip_addr as *const c_void)?;
1040
1041        if let Some(ref addr_details) = self.rip_addr_details {
1042            if let Some(ref fname) = addr_details.file_name {
1043                let sname = addr_details
1044                    .sym_name
1045                    .as_ref()
1046                    .map(String::as_str)
1047                    .unwrap_or("<unknown>");
1048                write!(f, " (symbol {}:{})", fname, sname)?;
1049            }
1050            if addr_details.in_module_code {
1051                write!(f, " (inside module code)")
1052            } else {
1053                write!(f, " (not inside module code)")
1054            }
1055        } else {
1056            write!(f, " (unknown whether in module)")
1057        }
1058    }
1059}
1060
1061/// Information about a terminated guest.
1062///
1063/// Guests are terminated either explicitly by `Vmctx::terminate()`, or implicitly by signal
1064/// handlers that return `SignalBehavior::Terminate`. It usually indicates that an unrecoverable
1065/// error has occurred in a hostcall, rather than in WebAssembly code.
1066pub enum TerminationDetails {
1067    /// Returned when a signal handler terminates the instance.
1068    Signal,
1069    /// Returned when `get_embed_ctx` or `get_embed_ctx_mut` are used with a type that is not present.
1070    CtxNotFound,
1071    /// Returned when the type of the value passed to `Instance::resume_with_val()` does not match
1072    /// the type expected by `Vmctx::yield_expecting_val()` or `Vmctx::yield_val_expecting_val`, or
1073    /// if `Instance::resume()` was called when a value was expected.
1074    ///
1075    /// **Note**: If you see this termination value, please report it as a Lucet bug. The types of
1076    /// resumed values are dynamically checked by `Instance::resume()` and
1077    /// `Instance::resume_with_val()`, so this should never arise.
1078    YieldTypeMismatch,
1079    /// Returned when dynamic borrowing rules of methods like `Vmctx::heap()` are violated.
1080    BorrowError(&'static str),
1081    /// Calls to `lucet_hostcall_terminate` provide a payload for use by the embedder.
1082    Provided(Box<dyn Any + 'static>),
1083    Remote,
1084}
1085
1086impl TerminationDetails {
1087    pub fn provide<A: Any + 'static>(details: A) -> Self {
1088        TerminationDetails::Provided(Box::new(details))
1089    }
1090    pub fn provided_details(&self) -> Option<&dyn Any> {
1091        match self {
1092            TerminationDetails::Provided(a) => Some(a.as_ref()),
1093            _ => None,
1094        }
1095    }
1096}
1097
1098// Because of deref coercions, the code above was tricky to get right-
1099// test that a string makes it through
1100#[test]
1101fn termination_details_any_typing() {
1102    let hello = "hello, world".to_owned();
1103    let details = TerminationDetails::provide(hello.clone());
1104    let provided = details.provided_details().expect("got Provided");
1105    assert_eq!(
1106        provided.downcast_ref::<String>().expect("right type"),
1107        &hello
1108    );
1109}
1110
1111impl PartialEq for TerminationDetails {
1112    fn eq(&self, rhs: &TerminationDetails) -> bool {
1113        use TerminationDetails::*;
1114        match (self, rhs) {
1115            (Signal, Signal) => true,
1116            (BorrowError(msg1), BorrowError(msg2)) => msg1 == msg2,
1117            (CtxNotFound, CtxNotFound) => true,
1118            // can't compare `Any`
1119            _ => false,
1120        }
1121    }
1122}
1123
1124impl std::fmt::Debug for TerminationDetails {
1125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1126        write!(f, "TerminationDetails::")?;
1127        match self {
1128            TerminationDetails::Signal => write!(f, "Signal"),
1129            TerminationDetails::BorrowError(msg) => write!(f, "BorrowError({})", msg),
1130            TerminationDetails::CtxNotFound => write!(f, "CtxNotFound"),
1131            TerminationDetails::YieldTypeMismatch => write!(f, "YieldTypeMismatch"),
1132            TerminationDetails::Provided(_) => write!(f, "Provided(Any)"),
1133            TerminationDetails::Remote => write!(f, "Remote"),
1134        }
1135    }
1136}
1137
1138unsafe impl Send for TerminationDetails {}
1139unsafe impl Sync for TerminationDetails {}
1140
1141/// The value yielded by an instance through a [`Vmctx`](vmctx/struct.Vmctx.html) and returned to
1142/// the host.
1143pub struct YieldedVal {
1144    val: Box<dyn Any + 'static>,
1145}
1146
1147impl std::fmt::Debug for YieldedVal {
1148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1149        if self.is_none() {
1150            write!(f, "YieldedVal {{ val: None }}")
1151        } else {
1152            write!(f, "YieldedVal {{ val: Some }}")
1153        }
1154    }
1155}
1156
1157impl YieldedVal {
1158    pub(crate) fn new<A: Any + 'static>(val: A) -> Self {
1159        YieldedVal { val: Box::new(val) }
1160    }
1161
1162    /// Returns `true` if the guest yielded without a value.
1163    pub fn is_none(&self) -> bool {
1164        self.val.is::<EmptyYieldVal>()
1165    }
1166
1167    /// Returns `true` if the guest yielded with a value.
1168    pub fn is_some(&self) -> bool {
1169        !self.is_none()
1170    }
1171
1172    /// Attempt to downcast the yielded value to a concrete type, returning the original
1173    /// `YieldedVal` if unsuccessful.
1174    pub fn downcast<A: Any + 'static>(self) -> Result<Box<A>, YieldedVal> {
1175        match self.val.downcast() {
1176            Ok(val) => Ok(val),
1177            Err(val) => Err(YieldedVal { val }),
1178        }
1179    }
1180
1181    /// Returns a reference to the yielded value if it is present and of type `A`, or `None` if it
1182    /// isn't.
1183    pub fn downcast_ref<A: Any + 'static>(&self) -> Option<&A> {
1184        self.val.downcast_ref()
1185    }
1186}
1187
1188/// A marker value to indicate a yield or resume with no value.
1189///
1190/// This exists to unify the implementations of the various operators, and should only ever be
1191/// created by internal code.
1192#[derive(Debug)]
1193pub(crate) struct EmptyYieldVal;
1194
1195fn default_fatal_handler(inst: &Instance) -> ! {
1196    panic!("> instance {:p} had fatal error: {}", inst, inst.state);
1197}