Crate sandkiste_lua

source ·
Expand description

Using the Lua programming language with the sandkiste sandboxing API

Features

This crate allows executing Lua code in a sandbox where memory usage and the number of executed Lua instructions can be limited.

It uses the sandkiste API, which is an interface that can also be used for sandboxing other scripting languages than Lua.

It is possible to call Lua functions from Rust or to call Rust closures from Lua. However, execution time in Rust (or waiting for I/O) is not counting towards resource limits.

Different Lua versions

Upon building, either Lua version 5.3 or 5.4 must be selected by specifying one of the features Lua5_3 or Lua5_4. Currently, it is not possible to build this crate with support for both Lua versions at the same time.

To allow lifting this restriction in future, items are contained in a module reflecting the Lua version being used (module v5_3 or v5_4).

Example use

use sandkiste::prelude::*;
#[cfg(feature = "Lua5_3")]
use sandkiste_lua::v5_3::{LuaMachine, LuaDatum};
#[cfg(feature = "Lua5_4")]
use sandkiste_lua::v5_4::{LuaMachine, LuaDatum};
use std::cell::RefCell;

let output_cell = RefCell::new(String::new());

let machine = LuaMachine::new();

machine.load_stdlib().expect("could not load Lua standard lib");
machine
    .compile(
        Some("init".to_string()),
        "-- require 'some_library'",
    )
    .expect("could not compile initialization code")
    .call([])
    .expect("could not run initialization code");

// remove certain functions from Lua's standard library:
machine.seal().expect("could not seal sandbox");

let my_print = machine
    .callback_1arg(|s| {
        let s = s.try_as_str()?;
        let mut output = output_cell.borrow_mut();
        output.push_str(s);
        Ok([])
    })
    .expect("could not create closure for myprint");
machine
    .compile(
        Some("set_myprint".to_string()),
        "myprint = ...",
    )
    .expect("could not compile code to set myprint")
    .call([my_print])
    .expect("could not run code to set myprint");

let main = machine
    .compile(
        Some("main".to_string()),
        "\
            local args = {...}\n\
            myprint('Hello ')\n\
            myprint(args[1])\n\
            myprint('!')\n\
        "
    )
    .expect("could not compile main Lua function");

let name: LuaDatum = "Rust".into();
main.call([name]).expect("runtime error in main Lua function");

// dropping these lets us move out of `output_cell`, which is still
// borrowed by the closure that has been moved to the machine:
drop(main);
drop(machine);

let output = output_cell.into_inner();
assert_eq!(output, "Hello Rust!");

Modules

  • Foreign function interface for C part of implementation (including C bindings for Lua)
  • Support for Lua 5.3