Skip to content
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

False positive if err variable is reused/redeclared #49

Open
kolyshkin opened this issue Aug 2, 2023 · 2 comments
Open

False positive if err variable is reused/redeclared #49

kolyshkin opened this issue Aug 2, 2023 · 2 comments

Comments

@kolyshkin
Copy link
Contributor

I am seeing an false positive in the following code (example.go):

package main

import (
        "fmt"
        "io"
        "os"
)
  
func OsPipeFileReadReuseErrVar() {
        var buf [4096]byte
        r, _, err := os.Pipe()
        _, err = r.Read(buf[:])
        if err == io.EOF {
                fmt.Println(err)
        }
}

With the following added diagnostics:

diff --git a/errorlint/allowed.go b/errorlint/allowed.go
index d4274b8..faa0d61 100644
--- a/errorlint/allowed.go
+++ b/errorlint/allowed.go
@@ -126,6 +126,7 @@ func isAllowedErrorComparison(info *TypesInfoExt, binExpr *ast.BinaryExpr) bool
        // All assignments done must be allowed.
        for _, funcName := range functionNames {
                if !isAllowedErrAndFunc(errName, funcName) {
+                       fmt.Printf("err: %s fun: %s\n", errName, funcName)
                        return false
                }
        }

I get this result:

$ go build .
$ ./go-errorlint ./example.go 
err: io.EOF fun: os.Pipe
/home/kir/go/src/github.com/polyfloyd/go-errorlint/example.go:13:5: comparing with == will fail on wrapped errors. Use errors.Is to check for a specific error

So, the linter thinks err comes from os.Pipe while actually it is from (*os.File).Read.

NOTE this is not a regression in cd16050 (reproduced on both git tip as well as v1.4.3).

@polyfloyd
Copy link
Owner

Hi!

If I recall correctly, the linter prefers the expression of the error's declaration to check with the allowlist. Reuse of the error variable by other assignments could be difficult as it would need to have knowledge of the control flow. Your example has the assignments happening in a predictable sequence, but what if branches or loops are involved?

I personally prefer writing function calls returning errors like this:

        if _, err := r.Read(buf[:]); err == io.EOF {
                fmt.Println(err)
        }

This should mitigate the reassignment problem as the error from r.Read now lives as a new variable. Not a solution, but it likely reduces the number of times one runs into this.

@kolyshkin
Copy link
Contributor Author

Alas, in some cases this is not possible. Here's a real world example:

        pipeR, pipeW, err := os.Pipe()  
        if err != nil {  
                return err  
        }  

        // ...

       // Read a single byte expecting EOF.  
        var buf [1]byte 
        n, err := pipeR.Read(buf[:]) 
        if n != 0 || err == nil { 
                return errUnexpectedRead  
        } else if errors.Is(err, os.ErrDeadlineExceeded) {  
                // Probably the other end doesn't support the sd_notify_barrier protocol.  
                logrus.Warn("Timeout after waiting 30s for barrier. Ignored.")  
                return nil  
        } else if err == io.EOF {
                return nil  
        } else {  
                return err  
        }  

This is sort of hard to rewrite to avoid a warning (without using a new variable, like err2).

Anyway, I guess this is not something that can be solved easily by this linter.

@kolyshkin kolyshkin changed the title False positive if err variable is reused False positive if err variable is reused/redeclared Sep 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants