-
-
Notifications
You must be signed in to change notification settings - Fork 378
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
staticcheck: detect marshaler implementations with wrong receiver types #911
Comments
I just got bitten by this, and it wasn't trivial to debug. (The ultimate failure occurred far away.) I'd love to see this in static check. Upstream issue: golang/go#22967. I'd suggest just flagging any MarshalJSON that uses a pointer receiver. Tracking down all uses of a type is ~impossible. |
@josharian, I'm afraid that that would generate way too many false positives for In the meantime, perhaps @dgryski's semgrep-go could implement that kind of check? |
I think staticcheck can tolerate some level of false positives(?). And a pointer receiver is a code rake; just because no one has stepped on it yet doesn't really make it a good idea. |
From what I've seen, Dominik strives to keep |
|
A quick grep through the Go code on my laptop shows a lot of MarshalJSON methods with pointer receivers. That's either a lot of broken code or a lot of false positives. |
@dgryski, probably a reasonable amount of false-positives, since the code actually works if pointers are used in the parent structure. See https://play.golang.org/p/VDQOP00xyv4. |
Pointer receivers used with MarshalJSON are code rakes. golang/go#22967 dominikh/go-tools#911 I just stepped on one, and it hurt. Turn them over. Signed-off-by: Josh Bleecher Snyder <[email protected]>
I'm definitely not comfortable with outright banning MarshalJSON implementations on pointer receivers. A lot of people use the rule of "if some methods on a type use pointer receivers, then all methods should", to keep method sets consistent. We'll have to make do with finding actual bugs. |
Pointer receivers used with MarshalJSON are code rakes. golang/go#22967 dominikh/go-tools#911 I just stepped on one, and it hurt. Turn it over. While we're here, optimize the code a bit. name old time/op new time/op delta MarshalJSON-8 184ns ± 0% 44ns ± 0% -76.03% (p=0.000 n=20+19) name old alloc/op new alloc/op delta MarshalJSON-8 184B ± 0% 80B ± 0% -56.52% (p=0.000 n=20+20) name old allocs/op new allocs/op delta MarshalJSON-8 4.00 ± 0% 1.00 ± 0% -75.00% (p=0.000 n=20+20) Signed-off-by: Josh Bleecher Snyder <[email protected]>
Pointer receivers used with MarshalJSON are code rakes. golang/go#22967 dominikh/go-tools#911 I just stepped on one, and it hurt. Turn it over. While we're here, optimize the code a bit. name old time/op new time/op delta MarshalJSON-8 184ns ± 0% 44ns ± 0% -76.03% (p=0.000 n=20+19) name old alloc/op new alloc/op delta MarshalJSON-8 184B ± 0% 80B ± 0% -56.52% (p=0.000 n=20+20) name old allocs/op new allocs/op delta MarshalJSON-8 4.00 ± 0% 1.00 ± 0% -75.00% (p=0.000 n=20+20) Signed-off-by: Josh Bleecher Snyder <[email protected]>
Pointer receivers used with MarshalJSON are code rakes. golang/go#22967 dominikh/go-tools#911 I just stepped on one, and it hurt. Turn it over. While we're here, optimize the code a bit. name old time/op new time/op delta MarshalJSON-8 184ns ± 0% 44ns ± 0% -76.03% (p=0.000 n=20+19) name old alloc/op new alloc/op delta MarshalJSON-8 184B ± 0% 80B ± 0% -56.52% (p=0.000 n=20+20) name old allocs/op new allocs/op delta MarshalJSON-8 4.00 ± 0% 1.00 ± 0% -75.00% (p=0.000 n=20+20) Signed-off-by: Josh Bleecher Snyder <[email protected]>
Oh silly me, we can do it the other way: look for calls to json.Marshal in which the concrete type has a value for which this will be a problem. |
nice! TIL! |
even if not enforced, this is super useful. for one, I was not aware of this. think 99% of devs are same. if this is not enforced linter, and purely for showing warnings and information to users — do you guys know how to call such tool? code-scanner? static-analyser? there is def value in such things! |
@nikolaydubina, that's a bit off-topic, and should generally be discussed in Discussions, not in issues. The general term seems to be “static analysis tools” or “linters”. |
Consider the following program:
https://play.golang.org/p/O54uPIT7x9z
A developer could assume that
MarshalJSON
will be called for all four fields of the structure, but in fact it's only called for theTS
field. The actual output, prettified:If we change the receiver of
MarshalJSON
from*T
toT
, it gets called for all fields as, probably, expected.As a simple and mostly false-positive-free first approximation, we could mark
MarshalJSON
implementations that have a pointer receiver, but are only used in JSON-encoded structures as non-pointer fields.I haven't inspected other encoders, like XML and YAML ones, but I assume they may have similar issues.
The text was updated successfully, but these errors were encountered: