-
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
gnovm doesn't perform terminating statement analysis #1086
Comments
@ajnavarro My proposal is to add static analysis as a step done in the preprocessor when finishing parsing a function literal or declaration. This is how we can catch the error at the preprocessing stage, before execution. |
What do you think about looping through all function statements, if the function is declared to return something and if there is non terminating statement, assert the function is ending with a return statement? gno/gnovm/pkg/gnolang/preprocess.go Line 462 in 1c6d184
|
That sounds reasonable. func Foo() {
a := func() int {
return 5
}
} And this PR needs to come with a lot of tests. |
approach/location looks good to me. Do note that whatever happens in FuncDecl should be matched with what happens with FuncLitExpr. Aside from that, looks good. Probably a good idea to iterate from the bottom and check using the "algorithm" here. Sorry for the delay getting back at you. |
Yea. I think, @KemalBekir should paste these rules from the Go spec as a comment next to the code that does the analysis. |
SGTM, you should proceed. Thank you. |
This PR solves: [This issue](#1086) - Added test for positive and negative outcomes - Implements the terminating description from the [Go spec:](https://go.dev/ref/spec#Terminating_statements) - Analysis performed during preprocessing --------- Co-authored-by: Petar Dambovaliev <petar.atanasov.1987@gmail.com>
Originally discovered by @petar-dambovaliev , re-discovered by me in development of gnochess.
This code is invalid Go code, but it is valid Gno at the time being. This results in a cryptic panic:
At the VM level, this is the difference between having a
return x
at the end ofy()
(red) and not having it (green):Key takeaways:
+v (9 int)
is not done, and as a consequence when definingz
inmain()
, the value popped is instead(y func()( int))
.This leads to the stacks not being effectively synchronised in popping/pushing, and to general corruption of the gnovm state, often leading to panics of various nature (the above is an example of around 3/4 I've seen).
The solution is properly implementing the Terminating Statement part of the spec, rejecting at pre-processing any function body which does not end in a terminating statement.
The official implementation for terminating statements seems to be the following: https://cs.opensource.google/go/go/+/refs/tags/go1.21.0:src/go/types/return.go;l=17
The text was updated successfully, but these errors were encountered: