use wasmtime::{Engine, Module, Store};
use crate::config::SandboxConfig;
use crate::error::{Error, Result};
use crate::observation::Observation;
#[derive(Debug, Clone)]
pub struct NestedWasmInfo {
pub module_size: usize,
pub import_names: Vec<String>,
pub export_names: Vec<String>,
pub instantiated: bool,
pub fuel_consumed: u64,
}
pub fn handle_wasm_instantiation(
engine: &Engine,
wasm_bytes: &[u8],
config: &SandboxConfig,
) -> Result<(NestedWasmInfo, Observation)> {
let module = Module::new(engine, wasm_bytes)
.map_err(|e| Error::Internal(format!("nested WASM compilation failed: {e}")))?;
let import_names: Vec<String> = module
.imports()
.map(|imp| format!("{}.{}", imp.module(), imp.name()))
.collect();
let export_names: Vec<String> = module.exports().map(|exp| exp.name().to_string()).collect();
let mut info = NestedWasmInfo {
module_size: wasm_bytes.len(),
import_names: import_names.clone(),
export_names: export_names.clone(),
instantiated: false,
fuel_consumed: 0,
};
if config.allow_nested_wasm && import_names.is_empty() {
let mut store = Store::new(engine, ());
if config.nested_wasm_max_fuel > 0 {
store
.set_fuel(config.nested_wasm_max_fuel)
.map_err(|e| Error::Internal(format!("nested fuel: {e}")))?;
}
let linker = wasmtime::Linker::new(engine);
if let Ok(_instance) = linker.instantiate(&mut store, &module) {
info.instantiated = true;
if config.nested_wasm_max_fuel > 0 {
let remaining = store.get_fuel().unwrap_or(0);
info.fuel_consumed = config.nested_wasm_max_fuel.saturating_sub(remaining);
}
} else {
info.instantiated = false;
return Ok((
info.clone(),
Observation::WasmInstantiation {
module_size: info.module_size,
import_names: info.import_names,
export_names: info.export_names,
},
));
}
}
let observation = Observation::WasmInstantiation {
module_size: info.module_size,
import_names: info.import_names.clone(),
export_names: info.export_names.clone(),
};
Ok((info, observation))
}