use std::error::Error;
use airsl::{
Engine, ExhaustedLimit, InstructionLimit, MemoryLimit, Policy, ResourceLimits, Script,
};
const RUNAWAY_LOOP: &str = "while true do end";
const RUNAWAY_ALLOCATION: &str =
"local held = {} while true do held[#held + 1] = string.rep('x', 4096) end";
const BOUNDED_LOOP: &str = "local n = 0 for _ = 1, 200000 do n = n + 1 end return n";
const TIGHT_INSTRUCTIONS: InstructionLimit = InstructionLimit::count(100_000);
const TIGHT_MEMORY: MemoryLimit = MemoryLimit::mebibytes(8);
fn main() -> Result<(), Box<dyn Error>> {
instruction_ceiling()?;
memory_ceiling()?;
ceilings_lifted()?;
Ok(())
}
fn instruction_ceiling() -> Result<(), Box<dyn Error>> {
let policy = Policy::confined()
.with_limits(ResourceLimits::none().with_instructions(Some(TIGHT_INSTRUCTIONS)));
let engine = Engine::builder().policy(policy).build()?;
let error = engine
.eval(&Script::from_source(RUNAWAY_LOOP, "runaway-loop")?)
.err()
.ok_or("the instruction ceiling did not stop a non-terminating script")?;
assert_eq!(error.exhausted_limit(), Some(ExhaustedLimit::Instructions));
println!("instruction ceiling: {error}");
println!(" classified as: {:?}", error.exhausted_limit());
Ok(())
}
fn memory_ceiling() -> Result<(), Box<dyn Error>> {
let policy =
Policy::confined().with_limits(ResourceLimits::none().with_memory(Some(TIGHT_MEMORY)));
let engine = Engine::builder().policy(policy).build()?;
let error = engine
.eval(&Script::from_source(RUNAWAY_ALLOCATION, "runaway-alloc")?)
.err()
.ok_or("the memory ceiling did not stop an unbounded allocation")?;
assert_eq!(error.exhausted_limit(), Some(ExhaustedLimit::Memory));
println!("memory ceiling: {error}");
println!(" classified as: {:?}", error.exhausted_limit());
Ok(())
}
fn ceilings_lifted() -> Result<(), Box<dyn Error>> {
let unbounded = Engine::builder()
.policy(Policy::confined().with_limits(ResourceLimits::none()))
.build()?;
let counted = unbounded.eval_to::<i64>(&Script::from_source(BOUNDED_LOOP, "bounded-loop")?)?;
println!("no ceilings: the bounded loop counted to {counted}");
let tight = Engine::builder()
.policy(
Policy::confined()
.with_limits(ResourceLimits::none().with_instructions(Some(TIGHT_INSTRUCTIONS))),
)
.build()?;
let stopped = tight.eval_to::<i64>(&Script::from_source(BOUNDED_LOOP, "bounded-loop")?);
println!(
"tight ceiling: the same bounded loop is stopped: {}",
stopped.is_err()
);
Ok(())
}