-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: cmd/vet: check for missing Err calls for bufio.Scanner and sql.Rows #17747
Comments
There are legitimate cases in which you might elide the s.Err check, such as when reading lines from a
How frequently is frequently? How bad are the resulting bugs? cc @robpike |
It probably comes up in code review at least once or twice per week. Typically when interacting with a database. As far as the severity of the resulting bugs, I am not sure. I'm on a different team and often just get asked to do code review sporadically, even though I typically don't maintain the projects where these problems occur. |
Perhaps a more proper place to implement this check is in the DeepGo tool since there is already a similar checker that handles missing calls on a resource.
|
How often do the things with Err methods get very complicated? A bigger question is whether something with an Err method should always have that method called. |
This proposal has been added to the active column of the proposals project |
The
Intraprocedural analysis seems sufficient for inferring that a NewScanner is called in the function, the value never escapes, and has no calls to Err(). Bottom up analysis is also going to be able to tell if the error return value in a (io.Reader).Read implementation is always the constant nil or an The challenge for checking |
If we cover only a predefined set of types such as |
The small sample of |
The most common patterns I see in a few examples are:
and
These are subject to a simple vet checker.
and
If "f()" return |
I am curious whether others think
Without more context about |
I still think that this is a valid checker, except that the check may need to be stricter. For the case whether the enclosing function return an error, the |
bufio.Scanner can return errors no matter what kind of reader is passed into it. It still sounds like this is doable with bottom-up summaries, since we have no interfaces with Err() error methods, so there's very little uncertainty about what is going on in any given function. The question remains: how many error reports would this produce, and are they useful? |
@twmb [or anyone else] Can you point to a real world example where you made either of these decisions? (Or provide an abstraction if it is proprietary?) The evidence I have looked at so far is a few dozen examples. All of this is code I did not write. I cannot see into the minds of what the authors were aware of or thinking. My best guess is that all of the ones I have looked at have a rare bug that is sneaking by. A real world example where the discussed check on |
Out of the repos I have lying that use
The most common trend for ignoring the error looks to be CLI tools that either (a) parse a single small line from stdin and fails if the input is anything other than an explicit "yes" or something, or (b) parse a well-defined small file for a specific line, where any non-match results in a separate error such that the scanner error unimportant. Less common are the few instances where best-effort parsing is fine, and the other instances where the scanner is parsing a small block of defined-in-program, size-already-validated chunk of text. FWIW there were more deliberate ignores than I was expecting -- I only remembered my own prior use cases (a very small amount of times in 10 years). I have a bunch of cli tools cloned. Of the four instances of code where the error potentially should be checked, one was obviously a bug, but looking at the surrounding code, the result will be logs that calculations are going wrong. Ultimately, whether this vet is accepted or not will not fundamentally affect me. I do question just how common it is that people are truly forgetting to check the error such that a hardline stance should be taken to block any instance of ignoring the error. |
@twmb I don't think I have enough context to make a judgement call on the "deliberately ignores error" examples you have listed. Can you share or point us at some of the "deliberately ignores error" examples? If it is not possible to provide the real version of that, is it possible to provide an abstracted version without proprietary details? |
Here's one: https://github.com/fastly/cli/blob/6150a454861ec683eb81d3566336b9aa57e34e50/pkg/commands/compute/language_rust.go#L332-L349 |
I saw multiple complaints about forgetting the check on social media in a short period, so I opened #51299. I don't have a good way to check a corpus, but my belief is that it is a fairly common mistake. |
Thank you for the example! This really moves the conversation forward. I'll try to condense this down to what I think its core is.
Basically whenever This is semi-plausible as a false positive. Satisfying the checker is imposing some cost here. Personally I do not think the costs of asking for I am not convinced we are out an acceptable cost-benefit tradeoff for a vet checker yet. I think we need more examples and evidence though. Might require a more systematic approach? In the meantime, if there are other real world examples folks think might be false positives those would really help. |
@timothy-king, it sounds like we should investigate the effect of checking for sql.Rows's Err method as well. |
To me, the difference between I'd be far more happy with a generic But a generic check for |
@Merovius, I don't think the analogy to The It's safe to ignore an error from It's safe to ignore an error from |
@Merovius @bcmills My intuition tells me that
so the API is sort of split, where the return type of |
@bcmills Hm. I'm not sure I agree. I quickly grepped through the stdlib and there are three To me, " Maybe the rule-ish is " In any case. I still don't like this check. Personally, I just really dislike having to write |
There could be a variant on bufio.Scanner with no Err method for use when you know you don’t care about the error. 🚲 bufio.LaxScanner? |
FWIW @Merovius I think of Close's error as only being about failed writes before the close. You shouldn't have to check Close's result on a read-only stream, and that's what most of these are. |
It sounds like it would be reasonable to write a checker for bufio.Scanner and sql.Rows not having their Err methods called. We can see what the precision is on the latter, but the former seems OK. Does anyone object to moving forward with this? |
These are the two most common stdlib misuses I have run into, so SGTM. |
Based on the discussion above, this proposal seems like a likely accept. |
I would like to collect more evidence before we make a decision here. I can volunteer to do this. Specifically I want to look at a few dozen more scanner.Err() cases for false positive prevalence and a couple dozen sql.Rows's Err cases. It may be a couple of weeks before I get to it though. |
This comment was marked as off-topic.
This comment was marked as off-topic.
Is this still on hold? |
I have not yet managed to collect the evidence I was hoping to. This may still take a while as we working on better ways of systematically testing such questions. |
We recently discovered that missing calls to This check (or something similar) would be very helpful for us. |
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (
go version
)?What operating system and processor architecture are you using (
go env
)?What did you do?
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
https://play.golang.org/p/zvrWRVgw4M
Used a
bufio.Scanner
without checkingbufio.Scanner.Err()
for error. The same mistake occurs frequently withsql.Rows.Err()
.What did you expect to see?
go vet
should warn thats.Err()
was not called, and that it should be checked to determine if an error occurred while scanning.This frequently occurs in our internal codebase at work. Arguably,
go vet
could check if any type has a methodErr() error
and report if the error is not checked or returned, instead of just checking the special cases withbufio.Scanner
andsql.Rows
. There may also be more types that use this pattern in the standard library.What did you see instead?
No warnings from
go vet
.The text was updated successfully, but these errors were encountered: