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
{{ message }}
Repository navigation
Run() returns nil for exit/exit!/abort: an embedder cannot tell a finished program from a stopped one #773
ruby.Run returns nil for a program that stopped itself, so an embedder cannot tell "finished" from "stopped".
Measured through the public API with a four-line Go embedder (not the rbgo CLI, which configures things Run does not):
abort "fatal: tenant failed" -> Run returned err=<nil> (and "fatal: tenant failed" written to out)
exit 3 -> Run returned err=<nil>
exit!(42) -> Run returned err=<nil>
raise "boom" -> Run returned err=RuntimeError: boom
MRI exits 1 / 3 / 42 / 1 respectively. So the one case that is reported is the exception; the three that stop the program are indistinguishable from success, and abort's message lands in out looking like ordinary program output.
This is structural rather than an oversight, which is why it needs an API decision and not a patch: cmd/rbgo/exit_status.go recovers the status with machine.TerminalExit() / machine.ExitingSplit(err), but run.go does
_, err=vm.New(out).Run(iseq)
discarding the *vm.VM. Since internal/vm is unreachable from outside the module, no embedder can recover what the CLI recovers.
Shapes worth considering, in rough order of how little they commit to:
A second entry point — RunStatus(src string, out io.Writer) (int, error) — leaving Run untouched.
A sentinel error type (*ruby.ExitError{Code int}) returned by Run, so existing callers that only check err != nil start seeing exits as non-nil. That is a behaviour change for current callers and should be called out as one.
The documentation in #770 also pins the current behaviour in readme_embedding_contract_test.go, so whichever shape is chosen, that test is the thing to update — deliberately, rather than discovering the contract changed.
Activity
docs: the embedding contract says nothing is shared between Runs; pro…
fix(vm): preserve the cause and the cleanup, but keep propagating (#777)
fix(vm): guard Ruby-sized allocations against the bound that fails, a…