Skip to main content

outl_exec/wasm/
engine.rs

1//! `wasmtime::Engine` factory + sandbox knobs.
2//!
3//! We build the engine once per runtime instance (engines are cheap to
4//! share — modules are the heavy thing) and clone it into every store.
5//! The configuration is the **single source of truth** for what
6//! "sandboxed" means in outl:
7//!
8//! - Fuel on (consume_fuel = true) → caller decides how many
9//!   instructions a run gets.
10//! - Epoch interruption on → caller bumps the engine's epoch from a
11//!   timer thread for wall-clock cancellation. Today
12//!   [`crate::sandbox::with_timeout`] still does the thread-based
13//!   timeout; the epoch path is wired up so an upcoming refactor can
14//!   move to it without a config churn.
15
16use wasmtime::{Config, Engine, OptLevel};
17
18/// Sandbox limits a single `execute` call may use.
19///
20/// The defaults are conservative: 1 million instructions, 64 MiB heap,
21/// no growth beyond that. Callers tighten as needed (a tiny snippet
22/// running in a TUI loop deserves much less than a long batch job).
23#[derive(Debug, Clone, Copy)]
24pub struct SandboxLimits {
25    /// Maximum wasm instructions the run may execute. wasmtime calls
26    /// this "fuel"; one unit ≈ one instruction.
27    pub fuel: u64,
28    /// Hard cap on heap, in bytes. Past this, wasmtime traps.
29    pub max_memory_bytes: usize,
30}
31
32impl Default for SandboxLimits {
33    fn default() -> Self {
34        Self {
35            fuel: 5_000_000,
36            max_memory_bytes: 64 * 1024 * 1024,
37        }
38    }
39}
40
41/// Build a `wasmtime::Engine` with the outl sandbox configuration.
42/// Cheap to call; reuse the result across `WasmModule` instances when
43/// possible.
44pub fn make_engine() -> Engine {
45    let mut cfg = Config::new();
46    cfg.consume_fuel(true);
47    cfg.epoch_interruption(true);
48    cfg.cranelift_opt_level(OptLevel::Speed);
49    // WASI requires multi-memory and bulk-memory; both enabled by
50    // default on recent wasmtime, but be explicit.
51    cfg.wasm_multi_memory(true);
52    cfg.wasm_bulk_memory(true);
53    Engine::new(&cfg).expect("wasmtime Config we control is always valid")
54}