-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/vet: Formatting string check cannot see through type assertions or varargs #70814
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
Comments
CC @golang/tools-team |
MyPrintf has a bug: it crashes if passed as non-string first argument. If you change the type of the first parameter to string, the static checker will do the right thing. Even assuming the real MyPrintf (from which you distilled this example) is more robust, it is still very confusing to the human reader to encounter a function named for printf that doesn't have a format string parameter. I don't think there's anything for the tools to do here. |
This kind of overloading is a recipe for mistakes. (How popular is it really? I would certainly push back if I ever saw it in a code review.) It is sufficient to expose just the printf variant and require the caller to say printf("%s", x) if they already have a string. Alternatively, expose a println variant as well. |
The real code appears to be https://github.com/stretchr/testify/blob/master/assert/assertions.go#L286-L301 :
This function seems to be buried kinda deep down under multiple layers. I agree with the skepticism that this overloading is a good idea compared to an explicit formatting string, but it is out there. The repo https://github.com/stretchr/testify has 23.6k stars on github. |
Yes there is? This code already exists in the wild; I've also encountered it in logging frameworks. Simply saying that it's not something you would write is a little bit dismissive. Of course, I could simply write an analyzer myself, but I would prefer users actually got a warning for this.
It's not a bug, it's a documented part of the function that it panics if the first argument isn't a string. This perfectly sensible program, and connecting the argument to the use is straightforward dataflow analysis. You can argue about whether or not this should be able to see through conditional selection of values, or through manifestly constant (i.e, it would be constant-evaluated in SSA), but that is not what I suggested in my original post. |
I would write the contract for
That second sentence is a doozy. It is also TBH a foot gun as the "printf formatting string" is easy to silently miss and get through testing. It is what the new check is trying to address. (I would argue this is not actually a very good API personally.) FWIW we applied this to our old code, mostly uncovered latent bugs, found a few examples like the Going back to https://github.com/stretchr/testify , the first function I happened to look at was
I ran this with go1.23.1 and got the following output:
The interesting bit is the "%!(EXTRA string=second argument)" in the output. It is interpreting |
Go version
go version go1.23.0 darwin/arm64
Output of
go env
in your module/workspace:What did you do?
Consider the following program:
I ran go vet on this program.
What did you see happen?
When running go vet, I expect to see a finding for an invalid formatting string in the call to
MyPrintf
. This is following the guidance in go vet's documentation to use a call to a fmt function to help it identify arguments that are formatting strings.Unfortunately, it appears that vet cannot see through either the varargs access (with constant index) nor through the type assertion.
What did you expect to see?
No findings.
I expect a finding in this case, because taking an
...any
to convert into formatting in this way is a popular mechanism for making functions appear to be overloaded between a formatting a non-formatting version. The popular assert package uses this pattern heavily: https://pkg.go.dev/github.com/stretchr/testify/assert, so it is probably worthwhile to make sure this actually gets linted correctly (at the very least, the case of having vet see through both type assertions and constant indexing).The text was updated successfully, but these errors were encountered: