| package a |
| |
| import ( |
| "log" |
| "os" |
| ) |
| |
| type X struct{ f, g int } |
| |
| func f(x, y *X) { |
| if x == nil { |
| print(x.f) // want "nil dereference in field selection" |
| } else { |
| print(x.f) |
| } |
| |
| if x == nil { |
| if nil != y { |
| print(1) |
| panic(0) |
| } |
| x.f = 1 // want "nil dereference in field selection" |
| y.f = 1 // want "nil dereference in field selection" |
| } |
| |
| var f func() |
| if f == nil { // want "tautological condition: nil == nil" |
| go f() // want "nil dereference in dynamic function call" |
| } else { |
| // This block is unreachable, |
| // so we don't report an error for the |
| // nil dereference in the call. |
| defer f() |
| } |
| } |
| |
| func f2(ptr *[3]int, i interface{}) { |
| if ptr != nil { |
| print(ptr[:]) |
| *ptr = [3]int{} |
| print(*ptr) |
| } else { |
| print(ptr[:]) // want "nil dereference in slice operation" |
| *ptr = [3]int{} // want "nil dereference in store" |
| print(*ptr) // want "nil dereference in load" |
| |
| if ptr != nil { // want "impossible condition: nil != nil" |
| // Dominated by ptr==nil and ptr!=nil, |
| // this block is unreachable. |
| // We do not report errors within it. |
| print(*ptr) |
| } |
| } |
| |
| if i != nil { |
| print(i.(interface{ f() })) |
| } else { |
| print(i.(interface{ f() })) // want "nil dereference in type assertion" |
| } |
| } |
| |
| func g() error { return nil } |
| |
| func f3() error { |
| err := g() |
| if err != nil { |
| return err |
| } |
| if err != nil && err.Error() == "foo" { // want "impossible condition: nil != nil" |
| print(0) |
| } |
| ch := make(chan int) |
| if ch == nil { // want "impossible condition: non-nil == nil" |
| print(0) |
| } |
| if ch != nil { // want "tautological condition: non-nil != nil" |
| print(0) |
| } |
| return nil |
| } |
| |
| func h(err error, b bool) { |
| if err != nil && b { |
| return |
| } else if err != nil { |
| panic(err) |
| } |
| } |
| |
| func i(*int) error { |
| for { |
| if err := g(); err != nil { |
| return err |
| } |
| } |
| } |
| |
| func f4(x *X) { |
| if x == nil { |
| panic(x) |
| } |
| } |
| |
| func f5(x *X) { |
| panic(nil) // want "panic with nil value" |
| } |
| |
| func f6(x *X) { |
| var err error |
| panic(err) // want "panic with nil value" |
| } |
| |
| func f7() { |
| x, err := bad() |
| if err != nil { |
| panic(0) |
| } |
| if x == nil { |
| panic(err) // want "panic with nil value" |
| } |
| } |
| |
| func bad() (*X, error) { |
| return nil, nil |
| } |
| |
| func f8() { |
| var e error |
| v, _ := e.(interface{}) |
| print(v) |
| } |
| |
| func f9(x interface { |
| a() |
| b() |
| c() |
| }) { |
| x.b() // we don't catch this panic because we don't have any facts yet |
| xx := interface { |
| a() |
| b() |
| }(x) |
| if xx != nil { |
| return |
| } |
| x.c() // want "nil dereference in dynamic method call" |
| xx.b() // want "nil dereference in dynamic method call" |
| xxx := interface{ a() }(xx) |
| xxx.a() // want "nil dereference in dynamic method call" |
| |
| if unknown() { |
| panic(x) // want "panic with nil value" |
| } |
| if unknown() { |
| panic(xx) // want "panic with nil value" |
| } |
| if unknown() { |
| panic(xxx) // want "panic with nil value" |
| } |
| } |
| |
| func f10() { |
| s0 := make([]string, 0) |
| if s0 == nil { // want "impossible condition: non-nil == nil" |
| print(0) |
| } |
| |
| var s1 []string |
| if s1 == nil { // want "tautological condition: nil == nil" |
| print(0) |
| } |
| s2 := s1[:][:] |
| if s2 == nil { // want "tautological condition: nil == nil" |
| print(0) |
| } |
| } |
| |
| func unknown() bool { |
| return false |
| } |
| |
| func f11(a interface{}) { |
| switch a.(type) { |
| case nil: |
| return |
| } |
| switch a.(type) { |
| case nil: // want "impossible condition: non-nil == nil" |
| return |
| } |
| } |
| |
| func f12(a interface{}) { |
| switch a { |
| case nil: |
| return |
| } |
| switch a { |
| case 5, |
| nil: // want "impossible condition: non-nil == nil" |
| return |
| } |
| } |
| |
| type Y struct { |
| innerY |
| } |
| |
| type innerY struct { |
| value int |
| } |
| |
| func f13() { |
| var d *Y |
| print(d.value) // want "nil dereference in field selection" |
| } |
| |
| func f14() { |
| var x struct{ f string } |
| if x == struct{ f string }{} { // we don't catch this tautology as we restrict to reference types |
| print(x) |
| } |
| } |
| |
| func f15(x any) { |
| ptr, ok := x.(*int) |
| if ok { |
| return |
| } |
| println(*ptr) // want "nil dereference in load" |
| } |
| |
| func f16(x any) { |
| ptr, ok := x.(*int) |
| if !ok { |
| println(*ptr) // want "nil dereference in load" |
| return |
| } |
| println(*ptr) |
| } |
| |
| func f18(x any) { |
| ptr, ok := x.(*int) |
| if ok { |
| println(ptr) |
| // falls through |
| } |
| println(*ptr) |
| } |
| |
| // Regression test for https://github.com/golang/go/issues/65674: |
| // spurious "nil deference in slice index operation" when the |
| // index was subject to a range loop. |
| func f19(slice []int, array *[2]int, m map[string]int, ch chan int) { |
| if slice == nil { |
| // A range over a nil slice is dynamically benign, |
| // but still signifies a programmer mistake. |
| // |
| // Since SSA has melted down the control structure, |
| // so we can only report a diagnostic about the |
| // index operation, with heuristics for "range". |
| |
| for range slice { // nothing to report here |
| } |
| for _, v := range slice { // want "range of nil slice" |
| _ = v |
| } |
| for i := range slice { |
| _ = slice[i] // want "range of nil slice" |
| } |
| { |
| var i int |
| for i = range slice { |
| } |
| _ = slice[i] // want "index of nil slice" |
| } |
| for i := range slice { |
| if i < len(slice) { |
| _ = slice[i] // want "range of nil slice" |
| } |
| } |
| if len(slice) > 3 { |
| _ = slice[2] // want "index of nil slice" |
| } |
| for i := 0; i < len(slice); i++ { |
| _ = slice[i] // want "index of nil slice" |
| } |
| } |
| |
| if array == nil { |
| // (The v var is necessary, otherwise the SSA |
| // code doesn't dereference the pointer.) |
| for _, v := range array { // want "nil dereference in array index operation" |
| _ = v |
| } |
| } |
| |
| if m == nil { |
| for range m { // want "range over nil map" |
| } |
| m["one"] = 1 // want "nil dereference in map update" |
| } |
| |
| if ch == nil { |
| for range ch { // want "receive from nil channel" |
| } |
| <-ch // want "receive from nil channel" |
| ch <- 0 // want "send to nil channel" |
| } |
| } |
| |
| func f20() { |
| f, err := os.Open("") |
| if err != nil { |
| log.Fatal(err) // noreturn analysis proves this call doesn't return |
| } |
| if err != nil { // want "impossible condition" |
| log.Fatal(err) |
| } |
| f.Close() |
| } |