go vet: Printf family check

What?

I use golang with VSCode IDE. One of the features that I enabled is on-fly static code analysis. It uses standard golang feature Command Vet https://golang.org/cmd/vet. This article is about interesting Printf family check https://golang.org/cmd/vet/#hdr-Printf_family behaviour. If write a code

err := fmt.Errorf("Unexpected values %v , %v", v1)

go vet reports “Missing argument for Errorf(“%v”): format reads arg2, have on”.

go vet for non-standard functions?

There is a famous third party package https://github.com/pkg/errors that provides simple error handling primitives. Namely

// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is call, and the format specifier.
func Wrapf(err error, format string, args ...interface{}) error

// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
func Errorf(format string, args ...interface{}) error

You may see from function declaration that there are no  specific attributes for Printf family methods, like appropriate extension of C++ compilers __attribute__((__format__ (__printf__,...) or Microsoft SAL Annotations.

But go vet checks and reports problem for Errorf and doesn’t for Wrapf! In fact, documentation of Command Vet explains it, let’s look again https://golang.org/cmd/vet/#hdr-Printf_family

Flag: -printf
Suspicious calls to functions in the Printf family, including any functions with these names, disregarding case: ... 

The -printfuncs flag can be used to redefine this list.

It means we can configure go vet to check Wrapf function too! Source code https://golang.org/src/cmd/vet/print.go clarifies the following:

  • -printfuncs adds given name to existing list (“redefine” word in doc is unclear).
  • format string is auto-detected: the last parameter before variadic arguments or the first string literal or string constant is assumed to be a format string). Improved  checking was added at go1.7.

What to do?

Command line

Update your build scripts to run go vet with printf functions. Usually I check most common names:

go vet -printfuncs=wrapf,statusf,warnf,infof,debugf,failf,equalf,containsf


config.go:53: missing argument for Wrapf("%v"): format reads arg 2, have only 1 arg

IDE settings

Add Printf-like functions to you IDE config. For VSCode, I added to settings.json flag:

“go.vetFlags”: [“printfuncs=wrapf”]

GoVetWrapf

Code Review portal

I use Phabricator and Arconist for team code reviews https://secure.phabricator.com/book/phabricator/article/arcanist. It supports different linters including govet linter. You can add specific flags into .arclint file of your repository (see template at https://github.com/kalbasit/arcanist-go/blob/master/README.md):

"govet": {
    "flags": ["-printfuncs=wrapf"],
    "include": [ "(\\.go$)" ],
    "type": "govet"
},

Now you can run arc lint

GoVetArcLint

Check and Test Function signature

When you declare method with the name from Printf family list, make sure that go vet can detect format string correctly. It must end with ‘f’ if you want go vet to check it as printf-like!Also if you declare format string outside, make sure that this is a constant

const msg ="Unexpected values %v , %v"
err := fmt.Errorf(msg, v1, v2)

Test will help you to make sure that format check works. This functionality has some pitfalls, look for instance at issue with functions from an imported package https://github.com/golang/go/issues/14754

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s