Skip to content

feat(lua): Python-style traceback + locals capture#448

Open
skhaz wants to merge 1 commit into
mainfrom
feat/lua-traceback-locals
Open

feat(lua): Python-style traceback + locals capture#448
skhaz wants to merge 1 commit into
mainfrom
feat/lua-traceback-locals

Conversation

@skhaz

@skhaz skhaz commented Jul 7, 2026

Copy link
Copy Markdown
Member

Python-style stack-trace + locals capture for Wippy Lua scripts, on demand.

Why

Lua scripts had no way to capture a stack trace with local variables — only a bare debug.traceback string with no locals, and even that was unavailable because SkipOpenLibs excluded the debug library entirely.

What

  • Read-only debug subset as a cached global (cached_libs.go): traceback, getinfo, getlocal, getupvalue. Stripped: setlocal, setmetatable, setupvalue, and getmetatable (the last bypasses __metatable — a sandbox hole).
  • traceback module (runtime/lua/modules/traceback):
    • traceback.format(level, opts) — formatted multi-line string (Python traceback.format_exc style).
    • traceback.frames(level, opts) — structured frames with locals and upvalues.
    • Options: depth, locals, upvalues, max_value_len, max_table_depth.
    • Cycle detection for self-referential tables; frames that panic under post-recover conditions are skipped instead of aborting the trace.
  • Registered as a core ambient module (core_modules.go) — require("traceback") and global.

Usage

-- On-demand snapshot
print(traceback.format(1))

-- At the throw site (xpcall handler runs with stack intact)
xpcall(risky, function(e) return traceback.format(1) end)

Dependencies

Bumps github.com/wippyai/go-lua to a pre-release commit (wippyai/go-lua#32) for two prerequisites: xpcall catching errors under direct PCall/DoString, and inspect.GetStackFrame capturing upvalues. Once wippyai/go-lua#32 merges and tags a release, the pseudo-version can be replaced with the tag.

Testing

  • TDD: RED → GREEN for the module, the cached-lib subset, and both fork fixes.
  • make test-runtime, make lint, gofmt, vet — green.
  • Mutation: 65% efficacy, 100% coverage; correctness-critical mutants killed.

Sample output (xpcall throw-site capture)

[3] <string>:6 (risky)
    Locals:
      depth = 0
      context = processing layer 0
      payload = {secret = shh, id = 0}
    Upvalues:
      risky = <function>

No visual/UI changes (runtime-only feature).

Why:
Lua scripts on Wippy had no way to capture a stack trace with local variables
— only a bare debug.traceback string with no locals, and even that was
unavailable because SkipOpenLibs excluded the debug library entirely. This adds
Python-style traceback + locals capture, on demand, for debugging and error
handlers.

What:
- Expose a read-only debug subset as a cached global (traceback, getinfo,
  getlocal, getupvalue); strip setlocal/setmetatable/setupvalue and
  getmetatable (the last bypasses __metatable, a sandbox hole).
- Add the traceback module (runtime/lua/modules/traceback) with format(level,
  opts) and frames(level, opts): structured frames carrying locals and
  upvalues, with cycle detection and depth/locals/upvalues/max_value_len/
  max_table_depth options. Frames that panic under post-recover conditions are
  skipped instead of aborting the trace.
- Register traceback as a core ambient module (require-able + global).
- Bump github.com/wippyai/go-lua to pick up xpcall catching errors under
  direct PCall/DoString and inspect.GetStackFrame now capturing upvalues,
  both prerequisites for throw-site capture from an xpcall handler.
@skhaz skhaz requested a review from wolfy-j July 7, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant