You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Summary: Output written via IO.print before a runtime trap is silently discarded. The captured stdout buffer is only returned to the CLI after successful execution; on trap the buffer is dropped as the exception unwinds.
Reproduction
public fn main(@Unit -> @Unit)
requires(true) ensures(true) effects(<IO>)
{
IO.print("line 1 before crash\n");
IO.print("line 2 before crash\n");
IO.print("line 3 before crash\n");
IO.print("line 4 before crash\n");
let @Nat = 42 / 0;
()
}
$ vera run /tmp/buffer_test.veraError: Runtime contract violation: error while executing at wasm backtrace: 0: 0x62 - <unknown>!mainCaused by: wasm trap: integer divide by zero
Expected: the four line N before crash lines precede the trap message. Actual: all four are lost.
Root cause
The IO.print host import in vera/codegen/api.py (host_print, ~line 450) appends the decoded UTF-8 to a Python io.StringIO named output_buf — it never writes to sys.stdout directly. The buffer is only surfaced to the CLI after the WASM call completes successfully:
On trap, the raise path unwinds without doing anything with output_buf. The CLI (vera/cli.py:605) only prints exec_result.stdoutafterexecute() returns normally. So on any trap, every prior IO.print byte is thrown away.
This is not the wasmtime runtime buffering anything — wasmtime-py calls host_print synchronously for each IO.print at the Vera source site; the buffering is entirely in our Python shim.
Impact
Debugging by inserting IO.print calls before a suspected crash site doesn't work — the prints never reach the terminal.
Conway's Game of Life session lost ~30 minutes to this: the agent inserted instrumentation prints, saw no output, concluded its changes weren't being exercised, and went looking for the wrong bug.
Flush on the trap path. In the except Exception as exc: block of execute() in vera/codegen/api.py, write output_buf.getvalue() (and stderr_buf.getvalue()) to sys.stdout/sys.stderr before re-raising — or attach them to the raised RuntimeError so vera/cli.py can print them alongside the trap message. Minimal change, localised, matches existing capture semantics.
Tee in the host import. Change host_print to write to output_bufandsys.stdout simultaneously (optionally only when capture=False; the test harness passes capture=True and wants the current behaviour). Live output, no buffering surprise, costs one extra write per IO.print.
Add IO.flush() as a new effect operation letting programs flush at explicit boundaries. Lower priority — (1) or (2) makes the common case work automatically.
(1) is the cheapest and fixes the reported symptom exactly. (2) is the most user-friendly but changes observable behaviour under vera run (output appears incrementally, not as a single block after the call returns). Probably ship (1) first, consider (2) as a follow-up.
Summary: Output written via
IO.printbefore a runtime trap is silently discarded. The captured stdout buffer is only returned to the CLI after successful execution; on trap the buffer is dropped as the exception unwinds.Reproduction
Expected: the four
line N before crashlines precede the trap message. Actual: all four are lost.Root cause
The
IO.printhost import invera/codegen/api.py(host_print, ~line 450) appends the decoded UTF-8 to a Pythonio.StringIOnamedoutput_buf— it never writes tosys.stdoutdirectly. The buffer is only surfaced to the CLI after the WASM call completes successfully:On trap, the
raisepath unwinds without doing anything withoutput_buf. The CLI (vera/cli.py:605) only printsexec_result.stdoutafterexecute()returns normally. So on any trap, every priorIO.printbyte is thrown away.This is not the wasmtime runtime buffering anything — wasmtime-py calls
host_printsynchronously for eachIO.printat the Vera source site; the buffering is entirely in our Python shim.Impact
IO.printcalls before a suspected crash site doesn't work — the prints never reach the terminal.Proposed fix
Three shapes, pick one or stack them:
except Exception as exc:block ofexecute()invera/codegen/api.py, writeoutput_buf.getvalue()(andstderr_buf.getvalue()) tosys.stdout/sys.stderrbefore re-raising — or attach them to the raisedRuntimeErrorsovera/cli.pycan print them alongside the trap message. Minimal change, localised, matches existing capture semantics.host_printto write tooutput_bufandsys.stdoutsimultaneously (optionally only whencapture=False; the test harness passescapture=Trueand wants the current behaviour). Live output, no buffering surprise, costs one extra write perIO.print.IO.flush()as a new effect operation letting programs flush at explicit boundaries. Lower priority — (1) or (2) makes the common case work automatically.(1) is the cheapest and fixes the reported symptom exactly. (2) is the most user-friendly but changes observable behaviour under
vera run(output appears incrementally, not as a single block after the call returns). Probably ship (1) first, consider (2) as a follow-up.Related
docs-skill-gapsthread leading to PR SKILL.md documentation sweep + bug tracking from Game of Life agent run (#513) #518.