Skip to content

Commit

Permalink
feat: introduces the RealmUnhandledPanicException type to represent…
Browse files Browse the repository at this point in the history
… an error thrown when a panic is not handled in the realm.
  • Loading branch information
omarsy committed Jul 25, 2024
1 parent 8f148b1 commit eead428
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 17 deletions.
7 changes: 5 additions & 2 deletions gno.land/pkg/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,12 +537,15 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) {
m.SetActivePackage(mpv)
defer func() {
if r := recover(); r != nil {
switch r.(type) {
switch r := r.(type) {
case store.OutOfGasException: // panic in consumeGas()
panic(r)
case gno.RealmUnhandledPanicException:
err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %s\nStacktrace: %s\n",
r.Descriptor, m.ExceptionsStacktrace())
default:
err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\nMachine State:%s\nStacktrace: %s\n",
r, m.String(), m.ExceptionsStacktrace())
r, m.String(), m.Stacktrace().String())
return
}
}
Expand Down
10 changes: 8 additions & 2 deletions gnovm/cmd/gno/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,14 @@ func listNonTestFiles(dir string) ([]string, error) {
func runExpr(m *gno.Machine, expr string) {
defer func() {
if r := recover(); r != nil {
fmt.Printf("panic running expression %s: %v\nMachine State:%s\nStacktrace: %s\n",
expr, r, m.String(), m.ExceptionsStacktrace())
switch r := r.(type) {
case gno.RealmUnhandledPanicException:
fmt.Printf("panic running expression %s: %v\nStacktrace: %s\n",
expr, r, m.ExceptionsStacktrace())

Check warning on line 194 in gnovm/cmd/gno/run.go

View check run for this annotation

Codecov / codecov/patch

gnovm/cmd/gno/run.go#L192-L194

Added lines #L192 - L194 were not covered by tests
default:
fmt.Printf("panic running expression %s: %v\nMachine State:%s\nStacktrace: %s\n",
expr, r, m.String(), m.Stacktrace().String())
}
panic(r)
}
}()
Expand Down
11 changes: 10 additions & 1 deletion gnovm/pkg/gnolang/debugger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,16 @@ func evalTest(debugAddr, in, file string) (out, err, stacktrace string) {

defer m.Release()
defer func() {
stacktrace = strings.TrimSpace(strings.ReplaceAll(m.ExceptionsStacktrace(), "../../tests/files/", "files/"))
if r := recover(); r != nil {
switch r.(type) {
case gnolang.RealmUnhandledPanicException:
stacktrace = m.ExceptionsStacktrace()
default:
stacktrace = m.Stacktrace().String()
}
stacktrace = strings.TrimSpace(strings.ReplaceAll(stacktrace, "../../tests/files/", "files/"))
panic(r)
}
}()

if debugAddr != "" {
Expand Down
3 changes: 1 addition & 2 deletions gnovm/pkg/gnolang/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ func TestEvalFiles(t *testing.T) {
t.Fatalf("unexpected error\nWant: %s\n Got: %s", wantErr, err)
}

if wantStacktrace != "" && !strings.Contains(stacktrace, wantStacktrace) ||
wantStacktrace == "" && stacktrace != "" {
if wantStacktrace != "" && !strings.Contains(stacktrace, wantStacktrace) {
t.Fatalf("unexpected stacktrace\nWant: %s\n Got: %s", wantStacktrace, stacktrace)
}
if wantOut != "" && out != wantOut {
Expand Down
2 changes: 1 addition & 1 deletion gnovm/pkg/gnolang/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (s Stacktrace) String() string {
fmt.Fprintf(&builder, " %s/%s:%d\n", call.Frame.Func.PkgPath, call.Frame.Func.FileName, call.Stmt.GetLine())
case call.Frame.GoFunc != nil:
fmt.Fprintf(&builder, "%s\n", toExprTrace(cx))
fmt.Fprintf(&builder, " %s\n", call.Frame.GoFunc.Value.Type())
fmt.Fprintf(&builder, " gofunction:%s\n", call.Frame.GoFunc.Value.Type())
default:
panic("StacktraceCall has a non-call Frame")

Check warning on line 133 in gnovm/pkg/gnolang/frame.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/frame.go#L132-L133

Added lines #L132 - L133 were not covered by tests
}
Expand Down
29 changes: 25 additions & 4 deletions gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ func (e Exception) Sprint(m *Machine) string {
return e.Value.Sprint(m)
}

// RealmUnhandledPanicException represents an error thrown when a panic is not handled in the realm.
type RealmUnhandledPanicException struct {
Descriptor string // Description of the unhandled panic.
}

func (e RealmUnhandledPanicException) String() string {
return e.Descriptor
}

//----------------------------------------
// Machine

Expand Down Expand Up @@ -775,8 +784,14 @@ func (m *Machine) resavePackageValues(rlm *Realm) {
func (m *Machine) RunFunc(fn Name) {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Machine.RunFunc(%q) panic: %v\nMachine State:%s\nStacktrace: %s\n",
fn, r, m.String(), m.ExceptionsStacktrace())
switch r := r.(type) {
case RealmUnhandledPanicException:
fmt.Printf("Machine.RunFunc(%q) panic: %v\nStacktrace: %s\n",
fn, r.Descriptor, m.ExceptionsStacktrace())
default:
fmt.Printf("Machine.RunFunc(%q) panic: %v\nMachine State:%s\nStacktrace: %s\n",
fn, r, m.String(), m.Stacktrace().String())

Check warning on line 793 in gnovm/pkg/gnolang/machine.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/machine.go#L787-L793

Added lines #L787 - L793 were not covered by tests
}
panic(r)
}
}()
Expand All @@ -786,8 +801,14 @@ func (m *Machine) RunFunc(fn Name) {
func (m *Machine) RunMain() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Machine.RunMain() panic: %v\nMachine State:%s\nStacktrace: %s\n",
r, m.String(), m.ExceptionsStacktrace())
switch r := r.(type) {
case RealmUnhandledPanicException:
fmt.Printf("Machine.RunMain() panic: %v\nStacktrace: %s\n",
r.Descriptor, m.ExceptionsStacktrace())
default:
fmt.Printf("Machine.RunMain() panic: %v\nMachine State:%s\nStacktrace: %s\n",
r, m.String(), m.Stacktrace())

Check warning on line 810 in gnovm/pkg/gnolang/machine.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/machine.go#L804-L810

Added lines #L804 - L810 were not covered by tests
}
panic(r)
}
}()
Expand Down
4 changes: 3 additions & 1 deletion gnovm/pkg/gnolang/op_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,9 @@ func (m *Machine) doOpPanic2() {
for i, ex := range m.Exceptions {
exs[i] = ex.Sprint(m)
}
panic(strings.Join(exs, "\n\t"))
panic(RealmUnhandledPanicException{
Descriptor: strings.Join(exs, "\n\t"),
})
}
m.PushOp(OpPanic2)
m.PushOp(OpReturnCallDefers) // XXX rename, not return?
Expand Down
15 changes: 11 additions & 4 deletions gnovm/tests/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error {
errstr = v.Sprint(m)
case *gno.PreprocessError:
errstr = v.Unwrap().Error()
case gno.RealmUnhandledPanicException:
errstr = v.Descriptor
default:
errstr = strings.TrimSpace(fmt.Sprintf("%v", pnc))
}
Expand Down Expand Up @@ -375,11 +377,16 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error {
}
}
case "Stacktrace":
if pnc == nil {
panic(fmt.Sprintf("fail on %s: got nil error, want: %q", path, stacktraceWanted))
}
if stacktraceWanted != "" {
stacktrace := m.ExceptionsStacktrace()
var stacktrace string

switch pnc.(type) {
case gno.RealmUnhandledPanicException:
stacktrace = m.ExceptionsStacktrace()
default:
stacktrace = m.Stacktrace().String()
}

if !strings.Contains(stacktrace, stacktraceWanted) {
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(stacktraceWanted),
Expand Down
20 changes: 20 additions & 0 deletions gnovm/tests/files/time17_native.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"fmt"
"time"
)

func main() {
now := time.Now()
now.In(nil)
}

// Error:
// time: missing Location in call to Time.In

// Stacktrace:
// now<VPBlock(1,0)>.In(gonative{*time.Location})
// gofunction:func(*time.Location) time.Time
// main<VPBlock(1,0)>()
// main/files/time17_native.gno:10

0 comments on commit eead428

Please sign in to comment.