Skip to content

Commit

Permalink
chore: recoverable panic in native functions
Browse files Browse the repository at this point in the history
Fix gnolang#663

Some panic invoked in native functions should be recoverable from gno
code. To do that, `panic` is replaced with `machine.Panic()` which
checks first beyond the call stack if there's a recover, before
panic-ing.
  • Loading branch information
tbruyelle committed Apr 12, 2023
1 parent 5b275ff commit 7e2cb69
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 6 deletions.
11 changes: 7 additions & 4 deletions gnovm/stdlibs/stdlibs.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ func InjectPackage(store gno.Store, pn *gno.PackageNode) {
func(m *gno.Machine) {
isOrigin := len(m.Frames) == 2
if !isOrigin {
panic("invalid non-origin call")
m.Panic(typedString("invalid non-origin call"))
return
}
},
)
Expand Down Expand Up @@ -314,13 +315,15 @@ func InjectPackage(store gno.Store, pn *gno.PackageNode) {
arg0 := m.LastBlock().GetParams1().TV
n := arg0.GetInt()
if n <= 0 {
panic("GetCallerAt requires positive arg")
m.Panic(typedString("GetCallerAt requires positive arg"))
return
}
if n > m.NumFrames() {
// NOTE: the last frame's LastPackage
// is set to the original non-frame
// package, so need this check.
panic("frame not found")
m.Panic(typedString("frame not found"))
return
}
var pkgAddr string
if n == m.NumFrames() {
Expand Down Expand Up @@ -426,7 +429,7 @@ func InjectPackage(store gno.Store, pn *gno.PackageNode) {
}
b32, err := bech32.ConvertAndEncode(prefix, bz)
if err != nil {
panic(err)
panic(err) // should not happen
}
res0 := gno.Go2GnoValue(
m.Alloc,
Expand Down
14 changes: 14 additions & 0 deletions gnovm/tests/files/std10.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "std"

func main() {
defer func() {
// assert panic is recoverable
println(recover())
}()
std.GetCallerAt(0)
}

// Output:
// GetCallerAt requires positive arg
14 changes: 14 additions & 0 deletions gnovm/tests/files/std11.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "std"

func main() {
defer func() {
// assert panic is recoverable
println(recover())
}()
std.GetCallerAt(42)
}

// Output:
// frame not found
14 changes: 14 additions & 0 deletions gnovm/tests/files/std9.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "std"

func main() {
defer func() {
// assert panic is recoverable
println(recover())
}()
std.AssertOriginCall()
}

// Output:
// invalid non-origin call
7 changes: 5 additions & 2 deletions gnovm/tests/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ func testPackageInjector(store gno.Store, pn *gno.PackageNode) {
func(m *gno.Machine) {
if !isOriginCall(m) {
m.Panic(typedString("invalid non-origin call"))
return
}
},
)
Expand Down Expand Up @@ -515,13 +516,15 @@ func testPackageInjector(store gno.Store, pn *gno.PackageNode) {
arg0 := m.LastBlock().GetParams1().TV
n := arg0.GetInt()
if n <= 0 {
panic("GetCallerAt requires positive arg")
m.Panic(typedString("GetCallerAt requires positive arg"))
return
}
if n > m.NumFrames()-1 {
// NOTE: the last frame's LastPackage
// is set to the original non-frame
// package, so need this check.
panic("frame not found")
m.Panic(typedString("frame not found"))
return
}
var pkgAddr string
if n == m.NumFrames()-1 {
Expand Down

0 comments on commit 7e2cb69

Please sign in to comment.