go: cmd/go2go: fuzzing triggers various crashes in type checker

What version of Go are you using (go version)?

My local go version used for the fuzzing:

$ go version
go version devel +4ba19b0188 Wed Jun 17 00:44:16 2020 +0000 linux/amd64

Does this issue reproduce with the latest release?

Yes with a recent git checkout dev.go2go

What operating system and processor architecture are you using (go env)?

linux/amd64

What did you do?

I tried fuzzing the type checker from the dev.go2go branch for a short period of time (roughly around 45 minutes) and was able to generate a variety of crashes. Here are six samples.

I realize this is still early days, and I suspect it is much more useful to have crashes or panics from code that actual humans wrote, but posting these examples of crashes in case there is interest in hardending against more corner cases, or perhaps using some as test cases in the future.

I was running fzgo, which is a prototype of making fuzzing a first class citizen in the go command (#19109).

The engine underneath fzgo is @dvyukov’s go-fuzz. I can post the fuzz function later if interested, but it was a cut down and slightly tweaked fuzz function adapted from https://github.com/dvyukov/go-fuzz-corpus/tree/master/gotypes.

These all crash on the current go2goplay.golang.org:

Crash 1: invalid memory address or nil pointer dereference

go/types.(*Checker).instantiate

package main
type nt(type )interface{g}
type ph(type e nt,g(d))s
func(*ph(e,e))h(d)

http://go2goplay.golang.org/p/7Jk4PT9GX3k

Crash 2: invalid memory address or nil pointer dereference

go/types.optype

package main
type Numeric interface{t}
func t(type T Numeric)(s[]T){0(){s[0][0]}}

https://go2goplay.golang.org/p/46EZOUKBLLu

Crash 3: invalid memory address or nil pointer dereference

go/types.IsInterface

package main
type d*interface{d.p}

https://go2goplay.golang.org/p/HChlkK2A_Di

Crash 4: invalid memory address or nil pointer dereference

go/types.(*Interface).Complete

package main
type Numeric interface{t}
func t(type T Numeric)(s[]T){if(0){*s[0]}}

https://go2goplay.golang.org/p/TwoY4k9kR1w

Crash 5: panic: multiplication of zero with infinity

math/big.(*Float).Mul

package main
func X(){7E700000000*0}

https://go2goplay.golang.org/p/avwOXp4HJrC

Crash 6: panic: assertion failed

go/types.(*Checker).shift

package main
func X(){0<<7E6000000000}

https://go2goplay.golang.org/p/pv_BlSJ9v5W


(Side note: it would be nice to be able to issue commands like go test -fuzz=. ./... (#19109) on the stdlib and elsewhere 😉

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 28 (15 by maintainers)

Commits related to this issue

Most upvoted comments

Crash 14 is caused by https://github.com/golang/go/blob/0a030888da0f33ef75111f079258ab78b1c3eb64/src/go/types/unify.go#L95 y is *types.Basic which have types.Invalid kind, so expand just returns y

and https://github.com/golang/go/blob/0a030888da0f33ef75111f079258ab78b1c3eb64/src/go/types/unify.go#L150-L157 recursive call.

Change https://github.com/golang/go/blob/0a030888da0f33ef75111f079258ab78b1c3eb64/src/go/types/unify.go#L94-L95 to

	x = expand(x)
	if basicX, ok := x.(*Basic); ok && basicX.Kind() == Invalid {
		return false
	}

	y = expand(y)
	if basicY, ok := y.(*Basic); ok && basicY.Kind() == Invalid {
		return false
	}

prevents endless recursion

@thepudds Thanks. I will look at these eventually, they are useful to test the corners of the implementation (keep in mind, this is still a prototype, and some pieces are pretty rough and known to be not correct for all cases).

Of the first batch, crashes 3, 5, and 6 are real. The others (1, 2, 4) don’t crash anymore on dev.go2go. 3, 5, and 6 are unrelated to generics and may also crash in the regular type checker (try go vet on them). If so, please file individual bugs against the regular go/types package.

I’ve got some more examples of some crashes that I found manually messing around with things, and this issue seemed like an appropriate place to put them.

Crash 7: panic: assertion failed

package main
type foo interface { bar() }
type x(type A) struct{ foo }
func main() { var _ foo = x(int){} }

https://go2goplay.golang.org/p/1VztHp6nDlp

Crash 8: fatal error: stack overflow

package main
type foo(type A) interface { type A }
func bar(type A foo(A))(a A) {}
func main() {}

https://go2goplay.golang.org/p/fX5PYaFHB1Z

Crash 9: internal compiler error: typecheck DCLFIELD

package main
type foo(type A) interface { type foo(A) }
func main() { var _ = new(foo(int)) }

https://go2goplay.golang.org/p/8-gvXzWvuky

This last one isn’t necessarily a crash, but I don’t know how to categorize it because it seems like some sort of unknown error class.

Crash 10: looping while expanding type

package main
type w(type A) struct{}
func (_ w(A)) Wrap() w(w(A)) { return w(w(A)){} }
func main() { var _ w(struct{}) }

https://go2goplay.golang.org/p/Vfv72Q_yFoS