I had a "nil pointer" bug that the compiler can't find out, but I'd like to see if there is a way to find it out by statically analyze it.
So the bug is like this:
package main
import (
"fmt"
)
type A struct {
name string
}
func newGoodA() (*A, error) {
return &A{
name: "Go",
}, nil
}
func newBadA() (*A, error) {
return nil, fmt.Errorf("failed to create A")
}
func (a *A) greet() string {
return "Hello " + a.name
}
func main() {
valueA, err := newBadA()
if err != nil {
fmt.Printf("Oops, failed because: %v", valueA.greet()) // This should be forbidden, because when err is not nil, valueA shouldn't be touched
}
}
When I run it, I had error, because valueA
is nil
.
panic: runtime error: invalid memory address or nil pointer dereference
This is a common mistake, but the compiler can't find out. I wonder if there is any tool that can statically analyze the code and find this out.
I feel it's possible if the rule is that:
If a function call returns a value and an error, then the if err != nil
logic should not touch that returned value (valueA
in this example), because that's dangerous, and most likely to be nil
.
Is there any tool can do this?
It's not correct to say that you cannot use valueA even if it is nil in the case of an error being returned by newBadA. Go will happily invoke the function on the nil receiver - for example:
func (a *A) greet() string {
if a == nil {
return "(nil)"
}
return a.name
}