-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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
cmd/vet: warn about using reflect.DeepEqual and == on reflect.Value #43993
Comments
A few minutes of searching github turned up a few instances. Both of these look like very confused code, where this vet check might at least point someone in the right direction: https://github.com/hedzr/assert/blob/e76ed4c3b339a79c3b788bc3fdf4605511203e14/equal.go lines 106-110 https://github.com/cuirixin/phoenix_corelib/blob/fb4035076004c2eca44d4840d390191e052a4d7b/libs/gotransformer/gotransformer_test.go line 19, 37, ... This one is probably someone who hit this bug, fixed their code, and left a comment about it: https://github.com/coreos/vcontext/blob/ee043618d38dc1daf804fe352433b5ce2428ea32/validate/validate_test.go lines 212-221 |
Another example (now fixed) at go-openapi/validate#137. |
Related: #18871 |
Perhaps we should define that when you pass a reflect.Value to DeepEqual, DeepEqual uses that directly instead of calling reflect.ValueOf on it. Then instead of warning about broken code we just make it not broken. |
That would work in my example case. Not sure what the right behavior is for, e.g., a struct with a |
I agree about not applying that to reflect.Value-typed fields, but vet was not going to catch those either. |
We have some history here where fmt.Print interprets a reflect.Value by using what it contains.
@ianlancetaylor says he ran into this recently due to a Go 1.16 internal change and it was not at all clear given the call (like in Keith's example at the top) that there was even a problem. So we should do either the vet change or the "make it work" change. I'm leaning toward "make it work". |
This proposal has been added to the active column of the proposals project |
Does anyone object to just making DeepEqual handle reflect.Value arguments by interpreting what the Values represent? |
typo? avoid calling |
Does it apply to |
It's not a typo. The current code is v1 := ValueOf(x)
v2 := ValueOf(y) The suggestion is to change that to something like var v1, v2 Value
xv, xok := x.(Value)
yv, yok := y.(Value)
if xok && yok {
v1 = xv
v2 = xv
} else {
v1 = ValueOf(x)
v2 = ValueOf(y)
} |
No.
No.
No. |
OK, I misinterpreted it affects user code. It affects std lib code actually. But is it required both of the arguments are
|
Good question. |
IMO |
Yeah, we just hit this as well with the following code in a validation library that was attempting to check zero value:
As it turns out, what it intended to do with a zero-value condition was incorrect, but the incorrect branch was never triggered before. We'll deal with fixing that issue in that particular library, but is it acceptable that the following code has a different result in go1.16 than it did in all prior go versions? func main() {
data := ""
fmt.Println(reflect.DeepEqual(reflect.Zero(reflect.TypeOf(data)), reflect.ValueOf(data)))
} Looks like https://go-review.googlesource.com/c/go/+/192331 was likely the relevant change |
@liggitt
|
Still probably worth a mention in the 1.16 release notes, since the externally visible behavior of reflect.Zero changed. Highlighting problematic comparisons of reflect.Values that would be affected would have prompted us to audit for that. |
It's only visible because of violations of
This issue (and #18871) was originally about highlighting problematic comparisons, hopefully more robustly than a release note would. i think we'll just end up fixing the behavior to do the right thing instead. |
Something like what was described in https://golang.org/doc/go1.10#reflect, describing the change made to the reflect package and describing potential impact for callers relying on incorrect or unspecified behavior. Perhaps something like:
|
Change https://golang.org/cl/300992 mentions this issue: |
Change https://golang.org/cl/302269 mentions this issue: |
… reflect.Value comparison Update golang/go#33136 Update golang/go#43993 Change-Id: I306a8fd60a4d58cfd338edea4f21690338bf9a0b Reviewed-on: https://go-review.googlesource.com/c/website/+/302269 Trust: Keith Randall <khr@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Given that everyone on Go 1.16 is already broken and we're not hearing a big uproar, it seems like a vet check and keeping the ValueOf semantics simpler is a better path forward. |
Based on the discussion above, this proposal seems like a likely accept. |
What about also flagging use of We'd have to allow comparing to the zero |
It seems OK to put the == check in as well, with an exception for reflect.Value{}. |
No change in consensus, so accepted. 🎉 |
Change https://golang.org/cl/308209 mentions this issue: |
Change https://golang.org/cl/308769 mentions this issue: |
Unfortunately, handling
These false positives seem like they may be common enough to warrant rolling back the I think maybe we do just |
To avoid false positives from the reflectvaluecompare checker #43993 Use v.IsValid() instead of var zero reflect.Value v != zero Also avoid comparing directly with the singleton reflect.Value representing a missing value. Detect the missing value by type instead. Change-Id: I3a00d63cf61c077e7c7ae816474aa1f032be325b Reviewed-on: https://go-review.googlesource.com/c/go/+/308769 Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Ian Lance Taylor <iant@google.com>
… reflect.Value comparison Update golang/go#33136 Update golang/go#43993 Change-Id: I306a8fd60a4d58cfd338edea4f21690338bf9a0b Reviewed-on: https://go-review.googlesource.com/c/website/+/302269 Trust: Keith Randall <khr@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This code doesn't do what you think it does:
It compares the internal details of the two
reflect.Value
structs, not their contents. The correct code would bereflect.DeepEqual(x.Interface(), y.Interface())
.I don't see any reason why you'd ever want to use
DeepEqual
on areflect.Value
. Hence no false positives.If you really wanted to compare two
reflect.Value
s (but you shouldn't),==
is equivalent toDeepEqual
.Seems like an easy mistake to make (see #43986 ). Not sure how common it might be, but I suspect it might be common enough to warrant a check.
The text was updated successfully, but these errors were encountered: