From 577480806454a5c8fa2f4e86d62e435cee86b202 Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Thu, 27 Mar 2025 22:05:09 -0500 Subject: [PATCH] update docs --- DOCS.md | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++- README.md | 109 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+), 2 deletions(-) diff --git a/DOCS.md b/DOCS.md index b611cfa..45205c0 100644 --- a/DOCS.md +++ b/DOCS.md @@ -1,4 +1,4 @@ -# LuaJIT Go Wrapper API Documentation +# API Documentation ## State Management @@ -361,6 +361,118 @@ Compiles and immediately executes Lua code. err := L.CompileAndRun("answer = 42", "test") ``` +## Sandbox Operations + +### NewSandbox() *Sandbox +Creates a new sandbox with standard libraries loaded. +```go +sandbox := luajit.NewSandbox() +defer sandbox.Close() +``` + +### Close() +Releases all resources used by the sandbox. +```go +sandbox.Close() +``` + +### Initialize() error +Sets up the environment system for the sandbox. +```go +err := sandbox.Initialize() +``` + +### RegisterFunction(name string, fn GoFunction) error +Registers a Go function in the sandbox. +```go +adder := func(s *luajit.State) int { + sum := s.ToNumber(1) + s.ToNumber(2) + s.PushNumber(sum) + return 1 +} +err := sandbox.RegisterFunction("add", adder) +``` + +### SetGlobal(name string, value any) error +Sets a global variable in the sandbox base environment. +```go +err := sandbox.SetGlobal("answer", 42) +``` + +### GetGlobal(name string) (any, error) +Retrieves a global variable from the sandbox base environment. +```go +value, err := sandbox.GetGlobal("answer") +``` + +### Run(code string) (any, error) +Executes Lua code in the sandbox and returns the result. +```go +result, err := sandbox.Run("return 40 + 2") +``` + +### RunFile(filename string) error +Executes a Lua file in the sandbox. +```go +err := sandbox.RunFile("script.lua") +``` + +### Compile(code string) ([]byte, error) +Compiles Lua code to bytecode. +```go +bytecode, err := sandbox.Compile("return 42") +``` + +### RunBytecode(bytecode []byte) (any, error) +Executes precompiled Lua bytecode in the sandbox. +```go +result, err := sandbox.RunBytecode(bytecode) +``` + +### LoadModule(name string) error +Loads a Lua module in the sandbox. +```go +err := sandbox.LoadModule("mymodule") +``` + +### SetPackagePath(path string) error +Sets the sandbox package.path. +```go +err := sandbox.SetPackagePath("./?.lua;/usr/local/share/lua/5.1/?.lua") +``` + +### AddPackagePath(path string) error +Adds a path to the sandbox package.path. +```go +err := sandbox.AddPackagePath("./modules/?.lua") +``` + +### AddModule(name string, module any) error +Adds a module to the sandbox environment. +```go +module := map[string]any{ + "version": "1.0", + "name": "mymodule", +} +err := sandbox.AddModule("mymod", module) +``` + +### AddPermanentLua(code string) error +Adds Lua code to the environment permanently. +```go +err := sandbox.AddPermanentLua(` + function hello(name) + return "Hello, " .. name .. "!" + end +`) +``` + +### ResetEnvironment() error +Resets the sandbox to its initial state. +```go +err := sandbox.ResetEnvironment() +``` + ## Package Path Operations ### SetPackagePath(path string) error @@ -407,6 +519,7 @@ err := s.safeCall(func() C.int { - Individual Lua states are not thread-safe - Create separate states for concurrent operations - Use the function registry to share functions between states +- Sandboxes are not thread-safe but provide mutex locking for their operations ## Memory Management @@ -422,4 +535,23 @@ Stack management requires manual attention: L.PushString("hello") // ... use the string L.Pop(1) // Clean up when done -``` \ No newline at end of file +``` + +Sandbox management: +```go +sandbox := luajit.NewSandbox() +defer sandbox.Close() +``` + +## Sandbox Best Practices + +- **Initialization**: Always call `Initialize()` before first use +- **Memory Management**: Use defer to ensure proper cleanup with `Close()` +- **Isolation**: Use separate sandboxes for unrelated script executions +- **Performance**: For frequently used code, compile to bytecode first +- **Error Handling**: Check error returns from all sandbox operations +- **Environment Management**: Reset the environment if state becomes corrupted +- **Library Control**: Use `AddModule()` to restrict available functionality +- **Resource Sharing**: Register functions with `RegisterFunction()` for better performance +- **Persistence**: Use `SetGlobal()` to maintain state between executions +- **Safety**: Use sandboxes for untrusted or user-provided code \ No newline at end of file diff --git a/README.md b/README.md index 113b046..3ffbf5d 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,54 @@ Use bytecode when you: - Want to precompile your Lua code - Are distributing Lua code to many instances +## Sandboxed Execution + +For more controlled execution, the sandbox provides isolation and environment management: + +```go +// Create a sandbox +sandbox := luajit.NewSandbox() +defer sandbox.Close() + +// Initialize the environment +err := sandbox.Initialize() + +// Register a function +adder := func(s *luajit.State) int { + sum := s.ToNumber(1) + s.ToNumber(2) + s.PushNumber(sum) + return 1 +} +sandbox.RegisterFunction("add", adder) + +// Run code in the sandbox +result, err := sandbox.Run(` + local result = add(40, 2) + return "The answer is: " .. result +`) +fmt.Println(result) // "The answer is: 42" + +// Add permanent functions to the environment +sandbox.AddPermanentLua(` + function square(x) + return x * x + end +`) + +// Run bytecode for better performance +bytecode, _ := sandbox.Compile(`return square(10)`) +result, _ = sandbox.RunBytecode(bytecode) +``` + +### When to Use the Sandbox + +Use the sandbox when you need: +- Isolated execution environments +- Persistent state between executions +- Control over available libraries and functions +- Enhanced security for untrusted code +- Better resource management for long-running applications + ## Registering Go Functions Want to call Go code from Lua? It's straightforward: @@ -139,15 +187,37 @@ for i := 0; i < 1000; i++ { } ``` +The sandbox also manages its environment efficiently: + +```go +// Environment objects are pooled and reused +for i := 0; i < 1000; i++ { + result, _ := sandbox.Run("return i + 1") +} +``` + ## Best Practices +### State Management - Always use `defer L.Close()` and `defer L.Cleanup()` to prevent memory leaks - Each Lua state should stick to one goroutine - For concurrent operations, create multiple states - You can share functions between states safely - Keep an eye on your stack management - pop as many items as you push + +### Bytecode Optimization - Use bytecode for frequently executed code paths - Consider compiling critical Lua code to bytecode at startup +- For small scripts (< 1024 bytes), direct execution might be faster + +### Sandbox Usage +- Call `Initialize()` before first use of a sandbox +- Use `defer sandbox.Close()` to ensure proper cleanup +- For persistent objects, add them with `SetGlobal()` +- Control available libraries with `AddModule()` +- For frequently used functions, use `RegisterFunction()` +- Reset the environment with `ResetEnvironment()` if state gets corrupted +- For maximum performance, compile scripts to bytecode first, then run with `RunBytecode()` ## Advanced Features @@ -193,6 +263,45 @@ L.GetGlobal("increment") L.Call(0, 1) // Returns 2 ``` +### Sandbox Environment Customization + +You can tailor the sandbox environment for specific needs: + +```go +// Add a custom module +myModule := map[string]any{ + "version": "1.0", + "config": map[string]any{ + "debug": true, + "maxItems": 100, + }, +} +sandbox.AddModule("myapp", myModule) + +// Add permanent Lua code +sandbox.AddPermanentLua(` + -- Utility functions available to all scripts + function myapp.formatItem(item) + return string.format("%s: %d", item.name, item.value) + end +`) + +// Use in script +result, _ := sandbox.Run(` + local item = {name="test", value=42} + return myapp.formatItem(item) +`) +``` + +## Performance Considerations + +- The sandbox adds a small overhead to execution but provides better isolation +- For maximum performance with the sandbox, use bytecode compilation +- The wrapper optimizes for common operations with specialized C helpers +- For small scripts (<1KB), direct execution with `DoString` is fastest +- For larger scripts or repeated execution, bytecode provides better performance +- Table operations are optimized for both array-like and map-like tables + ## Need Help? Check out the tests in the repository - they're full of examples. If you're stuck, open an issue! We're here to help.