PR

Go言語(Golang)標準の静的解析ツール「go vet」の使い方|バグになりそうな怪しいコードの調査

2. 基礎

こんにちは。Tomoyuki(@tomoyuki65)です。

Go言語(Golang)は標準機能が充実していますが、Go標準の静的解析ツールとして「go vet」コマンドがあります。

ただし、一般的なlintツールとは違っていて、「コンパイルは通るが、バグにつながる可能性が高いコードを検出する」ようなツールになっているため、その点は注意が必要です。

この記事では、そんな「go vet」コマンドの使い方についてご紹介します。

 

Go言語(Golang)標準の静的解析ツール「go vet」の使い方|バグになりそうな怪しいコードの調査

例えば以下のような変数の値をログ出力させるスクリプトがあったとします。

package main

import (
    "fmt"
)

func main() {
    name := "田中太郎"

    fmt.Printf("%d\n", name)
}

 

次に「go vet」コマンドを実行し、静的解析チェックをします。

go vet ./...

※必要に応じて適切なファイルパスを指定してチェックして下さい。

 

実行後、以下のようなメッセージがログ出力され、バグになりそうな怪しいコードをチェックできます。

※メッセージ内容「fmt.Printf format %d has arg name of wrong type string」の翻訳「fmt.Printfの書式指定子%dに対し、string型の引数nameが渡されています。」

 

また、チェック内容については、内部にある「アナライザー(修正アルゴリズム)」をもとにチェックしており、特定のアナライザーを指定してチェックも可能です。

 

アナライザー一覧(Go1.26の場合)

アナライザー 概要 主な検出対象・例
appends append の引数不足を検出 append(slice) のように追加する値がない呼び出し
asmdecl Go宣言とアセンブリの不整合を検出 アセンブリ関数の引数・戻り値サイズなどの不一致
assign 無意味な代入を検出 代入直後に上書きされ、値が一度も使われない
atomic sync/atomic のよくある誤りを検出 atomic操作対象のコピーなど
bools boolean演算のよくある誤りを検出 冗長・矛盾した真偽値条件
buildtag ビルドタグを検査 //go:build// +build の記述ミス
cgocall cgoのポインタ渡しルール違反を検出 GoポインタをC側へ不正に渡すケース
composites キーなし複合リテラルを検出 外部パッケージの構造体を T{a, b} のように初期化
copylocks lockを値コピーしてしまう問題を検出 sync.Mutex を含む構造体の値渡し・コピー
defers defer のよくある誤りを検出 defer の引数評価タイミングに関する問題
directive Goツールチェーン用ディレクティブを検査 //go:debug などの不正な指定
errorsas errors.As の誤った使用を検出 第2引数がポインタでない、error型として不適切
framepointer アセンブリのフレームポインタ破壊を検出 保存前にframe pointerを上書き
hostport net.Dial 等に渡すアドレス形式を検査 IPv6などで host:port 形式が不正
httpresponse HTTPレスポンス処理の誤りを検出 resp.Body の扱いなど、HTTP利用時の問題
ifaceassert 実現不可能なインターフェース型アサーションを検出 x.(SomeInterface) が型の関係上成立しない
loopclosure ループ変数をクロージャから参照する問題を検出 goroutineや無名関数で意図しないループ変数を参照
lostcancel context のCancelFuncを呼び忘れる問題を検出 context.WithCancel の戻り値 cancel を使用しない
nilfunc 関数値と nil の無意味な比較を検出 常に真・偽になる可能性がある比較
printf フォーマット文字列と引数の不整合を検出 %d にstringを渡す、引数不足など
shift ビット幅以上のシフトを検出 uint8 相当の値に対して8ビット以上のシフト
sigchanyzer os.Signal 用の非バッファチャネルを検出 シグナル受信用チャネルがunbuffered
slog log/slog の構造化ログ呼び出しを検査 key/valueの組み合わせ不正など
stdmethods 有名な標準インターフェースのメソッドシグネチャを検査 String()Error()MarshalJSON() 等の誤ったシグネチャ
stdversion 対象Goバージョンより新しい標準ライブラリAPIを検出 古いGoバージョン向けコードで新APIを使用
stringintconv string(int) 変換の誤解を検出 数値を文字列化するつもりで string(123) と書く
structtag struct tagの形式を検査 reflect.StructTag.Get で解釈できないタグ
testinggoroutine テスト中のgoroutineから Fatal 等を呼ぶ問題を検出 goroutine内の t.Fatal()t.FailNow()
tests テスト・Exampleのよくある誤用を検出 テスト関数やExampleの命名・使用ミス
timeformat Goの日時フォーマット指定ミスを検出 YYYY-MM-DD のような他言語形式を使用
unmarshal Unmarshal先として不適切な値を検出 非ポインタや不適切な値を渡す
unreachable 到達不能コードを検出 return の後に実行されない処理
unsafeptr uintptrunsafe.Pointer の危険な変換を検出 GCとの関係で不正になるポインタ変換
unusedresult 戻り値の未使用を検出 fmt.Sprintf()errors.New() 等の結果を捨てる
waitgroup sync.WaitGroup の誤用を検出 AddWait の不適切な並行使用など

※利用可能なアナライザー一覧は「go tool vet help」で確認できます。特定のアナライザーでチェックしたい場合は、「go vet -printf ./…」のように実行するとチェックできます。

 

スポンサーリンク

最後に

今回はGo標準の静的解析ツール「go vet」の使い方についてご紹介しました。

一般的なlintとは少し違うため、実際には他のツール(Staticcheckなど)も合わせて使うのを推薦しますが、Go標準で静的解析チェックができるのは便利です。

Go言語でバグになりそうな怪しいコードの調査をしたい場合は、ぜひ参考にしてみて下さい。

 

この記事を書いた人
Tomoyuki

SE→ブロガーを経て、現在はSoftware Engineer(Web/Gopher)をしています!

Tomoyukiをフォローする
2. 基礎
スポンサーリンク
Tomoyukiをフォローする

コメント

タイトルとURLをコピーしました