-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Go: Add query to check for deferred calls to functions which may return errors #11410
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
Conversation
QHelp previews: go/ql/src/InconsistentCode/DeferredErrorCall.qhelpDeferred call may return an errorWhen calling a function which may return an error, we should check whether an error has occurred and handle it in some meaningful way. Deferring a function call does not allow us to perform such a check. Therefore, calls to functions which may return errors should not be deferred. RecommendationExamine the deferred function call carefully to check whether any errors that may arise should be handled explicitly. ExampleIn the following example, a call to package main
import (
"io"
"log"
"os"
)
func example() {
defer io.WriteString(os.Stdout, "All done!")
if _, err := io.WriteString(os.Stdout, "Hello"); err != nil {
log.Fatal(err)
}
} To correct this issue, do not defer the function call that may return an error and handle the error explicitly instead: package main
import (
"io"
"log"
"os"
)
func example() {
if _, err := io.WriteString(os.Stdout, "Hello"); err != nil {
log.Fatal(err)
}
if _, err := io.WriteString(os.Stdout, "All done!"); err != nil {
log.Fatal(err)
}
} References
|
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 great.
Oh, I just realised that it needs a change note. Luckily there's an automatic check for that. Oh, and it needs docs review. I think you have to add the |
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.
Docs review: one typo, otherwise LGTM 👍
if _, err := io.WriteString(os.Stdout, "Hello"); err != nil { | ||
log.Fatal(err) | ||
} |
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.
Would it be possible to present a code example that preserves the behaviour we get from the usage of defer
, while still handling any errors that that callee may produce i.e. what if I wanted to defer
and also handle errors?
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.
Great question! It seems like there are techniques for doing this by deferring an anonymous function which captures and writes to an error variable, that is then returned by the parent function. I will modify the example to make use of that technique.
Co-authored-by: hubwriter <hubwriter@github.com>
From running this query on LGTM, it seems that it is currently quite noisy since it seems like a common (anti?)-pattern to defer calls to |
Since this query is very noisy and I am now working on more specific ones that are more targeted, I will close this PR for now in favour of new ones for the new queries as they are ready. |
A simple query which checks that there are no deferred calls to functions which may return errors, since it prevents errors from being handled.