go-openapi/validate

Go 1.16 will change behavior of what appears to be a buggy conditional

ianlancetaylor opened this issue · 0 comments

This line of code looks buggy to me:

https://github.com/go-openapi/validate/blob/master/type.go#L140

The troublesome code is:

reflect.DeepEqual(reflect.Zero(reflect.TypeOf(data)), reflect.ValueOf(data))

The function reflect.DeepEqual takes two different values of any type and returns whether they are "deep equal". It does not ordinarily take two different values of the type reflect.Value, because it is not normally interesting whether two different reflect.Value values are equal. What is interesting is whether the values stored in the reflect.Value values are equal.

Before Go 1.16, a call to reflect.Zero would internally store a pointer to a newly allocated zero value. Thus before Go 1.16 this expression would always return false (at least, I can't think of any cases where it would return true). In Go 1.16 that was changed by https://golang.org/cl/192331: as an optimization, reflect.Zero will now use the same pointer for all types smaller than 1024 bytes. The effect is that now if data was itself obtained by a call to reflect.Zero, the expression will now return true.

It appears that the code is trying to do something like

reflect.DeepEqual(reflect.Zero(reflect.TypeOf(data)).Interface(), data)

which as of Go 1.13 is more efficiently written as

reflect.ValueOf(data).IsZero()

I don't know what the right fix is here. Changing this code has various knock-on effects on other packages that use this one. Is an empty string really the same as a null value? I don't know.