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}