Skip to content

lean_vm: add source-level failure stack traces#246

Draft
latifkasuli wants to merge 1 commit into
leanEthereum:mainfrom
latifkasuli:fix/stack-traces
Draft

lean_vm: add source-level failure stack traces#246
latifkasuli wants to merge 1 commit into
leanEthereum:mainfrom
latifkasuli:fix/stack-traces

Conversation

@latifkasuli
Copy link
Copy Markdown

Summary

  • add source-level call-site metadata to compiled bytecode so runtime failures can reconstruct caller/callee frames from the VM frame chain
  • replace history-based stack guessing with a bounded, cycle-safe fp unwinder that prints frames from the failing function back to main
  • add ExecutionOptions / CompileAndRunOptions plus LEANVM_STACK_TRACE=0 for legacy callers to disable stack trace printing
  • preserve worker-local pc/fp for parallel_range failures and hide compiler-generated loop helper frames from the rendered stack

Closes #112.

Root cause

The existing diagnostic path inferred call stacks from source-location history. That could show useful source context, but it was not organized by the live caller/callee relation and could not reliably print the current VM frame chain from the failing function back to main.

Implementation notes

Touched surfaces:

  • crates/lean_compiler/src/b_compile_intermediate.rs
  • crates/lean_compiler/src/c_compile_final.rs
  • crates/lean_compiler/src/ir/instruction.rs
  • crates/lean_compiler/src/lib.rs
  • crates/lean_compiler/tests/test_compiler.rs
  • crates/lean_vm/src/diagnostics/stack_trace.rs
  • crates/lean_vm/src/execution/runner.rs
  • crates/lean_vm/src/isa/bytecode.rs

The unwinder follows the VM call convention (mem[fp] = return_pc, mem[fp + 1] = saved_fp) and has three safety guards: a 256-frame cap, repeated-fp detection, and checked memory reads. If the cap is hit while another frame is readable, the rendered trace includes a truncation marker.

Bytecode gains debug-only call-site metadata in call_sites_by_return_pc. I checked repository serialization usage: Bytecode does not derive or implement serde serialization/deserialization, and aggregation bytecode is compiled into a OnceLock at runtime rather than loaded from a persisted bytecode blob.

Sequencing / collision notes

This intentionally opens as a draft because the collision surface is real:

Validation

  • cargo test -p lean_compiler runtime_failure -- --nocapture
  • cargo test -p lean_compiler
  • cargo fmt --check
  • git diff --check
  • cargo check --workspace
  • cargo clippy --workspace --all-targets -- -D warnings

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.

Improved stack traces

1 participant