-
Notifications
You must be signed in to change notification settings - Fork 375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: invoke user recover with implicit panics #3067
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3067 +/- ##
==========================================
- Coverage 63.77% 63.74% -0.04%
==========================================
Files 548 548
Lines 78681 78773 +92
==========================================
+ Hits 50180 50215 +35
- Misses 25117 25164 +47
- Partials 3384 3394 +10
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
can you please add some tests for this? |
I tried a fix similar to this one: #2484, but my approach wasn't preferred. They favor an indiscriminate runtime panic, which complicates things for me (it is possible, but need a refactoring). I see two options:
|
its still WIP |
5b8936f
to
ce6141c
Compare
tests added |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GG for this PR, it's a great improvement! However, I have a small issue regarding some cases where error handling with recover
doesn't seem to work as expected. For example, in the Gno Native packages, like this one:
package main
import "time"
func main() {
defer func() {
r := recover()
println("recover:", r)
}()
t := time.Now()
t.In(nil)
}
The issue here is that t.In(nil)
causes an error, but there's no recovery mechanism for this situation. However, since Gno Native will no longer be supported in the future, perhaps we don't need to handle this case at this point.
We also have cases where panic occurs when we inject Go code injected into a Gno package. For example, this code:
package test
import "std"
func main() {
defer func() {
r := recover()
println("recover:", r)
}()
banker := std.GetBanker(std.BankerTypeRealmSend)
banker.SendCoins(std.CurrentRealm().Addr(), "", std.Coins{{"ugnot", 2000000000}})
}
I’ve seen this kind of panic occur, and I’m unsure if this should be recoverable.
Also, consider this case:
package test
import "time"
func main() {
defer func() {
r := recover()
println("recover:", r)
}()
println(time.UTC == nil)
time.UTC = nil
}
This could also cause an issue, and I’m not sure if this is something we should be able to recover from.
Just wanted to raise these points, but again, great job on this PR!
panicStmt := &PanicStmt{ | ||
Exception: &BasicLitExpr{Value: `"` + r.Sprint(m) + `"`, Kind: STRING}, | ||
} | ||
|
||
m.PushStmt(panicStmt) | ||
m.PushOp(OpExec) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this ?
panicStmt := &PanicStmt{ | |
Exception: &BasicLitExpr{Value: `"` + r.Sprint(m) + `"`, Kind: STRING}, | |
} | |
m.PushStmt(panicStmt) | |
m.PushOp(OpExec) | |
m.Panic(r.Value) |
Or Instead of panicking upon detecting a runtime panic, you can use m.Panic.
@@ -131,7 +131,11 @@ func (m *Machine) doOpQuoAssign() { | |||
} | |||
} | |||
// lv /= rv | |||
quoAssign(lv.TV, rv) | |||
err := quoAssign(lv.TV, rv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should hande this case too:
package main
func main() {
defer func() {
r := recover()
println("recover:", r)
}()
x, y := 10, 0
_ = x % y
}
@@ -145,6 +145,10 @@ func (m *Machine) doOpStar() { | |||
xv := m.PopValue() | |||
switch bt := baseOf(xv.T).(type) { | |||
case *PointerType: | |||
if xv.V == nil { | |||
panic(&Exception{Value: typedString("nil pointer dereference")}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this case will failed:
package main
type s struct {
el func()
}
func main() {
var el *s
defer func() {
recover()
}()
el.el()
}
@@ -0,0 +1,15 @@ | |||
package main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should consider this case too.
package main
func main() {
defer func() {
r := recover()
println("recover:", r)
}()
println(1/0)
}
We cannot recover it but maybe this should be failed on the preprocess
Currently only explicit panic invocations are recovered in the user code.
This PR covers the implicit panics that happen because of invalid operations.
Associated issue
This maintains the distinction between VM panics and user panics.
Here is a list of possible runtime panics that we will cover.