Cppcheck 1.73 dev
2015-09-09
イントロダクション
Cppcheck は C/C++の静的解析ツールです。C/C++ コンパイラやその他の解析ツールとは異なり、シンタックスエラーを検出しません。 その代わりに、Cppcheckは、コンパイラが通常、検出に失敗するような種類のバグを検出します。このプロジェクトのゴールは、擬陽性 0 です。
サポートしているプログラムのソースコードとプラットフォーム:
さまざまなコンパイラの拡張構文や、インラインアセンブル等を含む、非標準的なソースコードをチェックできます。
Cppcheck は 最新のC++規格をサポートしている、あらゆるC++コンパイラでコンパイルできるようにしています。
Cppcheck は 十分なCPUパワーとメモリーのある、あらゆるプラットフォームで動作するようにしています。
Cppcheckに限界があることをご理解ください。Cppcheckの報告しているエラーに稀に間違いのあることがあります。また、Cppcheck が検出しないバグが残っていることもあります。
ソフトウェアを注意深くテストすれば、Cppcheckを使うより、より多くのバグを検出することができるでしょう。ソフトウェアを注意深く実装すれば、Cppcheckを使うより、より多くのバグを検出することができるでしょう。しかし、あなたのソフトウェアを実装するときやテストするときに見逃したバグのいくつかを Cppcheckが検出できるでしょう。
はじめ方
最初のテスト
これは単純なソースコードです。
int main()
{
char a[10];
a[10] = 0;
return 0;
}
このソースコードをfile1.cに保存して次のコマンドを実行します。
cppcheck file1.c
cppcheck は次のように出力するでしょう。
Checking file1.c...
[file1.c:4]: (error) Array 'a[10]' index 10 out of bounds
フォルダ内の全てのファイルをチェックする
通常、プログラムは多くのソースファイルから構成されます。そして、それら全てをチェックしたいでしょう。Cppcheck は一つのディレクトリ以下の全てのソースファイルをチェックできます。
cppcheck path
ここで"path"はディレクトリのパスです。このようにすれば cppcheck はディレクトリ以下の全てのファイルを再帰的にチェックします。
Checking path/file1.cpp...
1/2 files checked 50% done
Checking path/file2.cpp...
2/2 files checked 100% done
チェックからファイルやフォルダを除外する
ファイルやフォルダをチェック対象から除外する方法は二つあります。最初の方法は、あなたがチェックしたいファイルやフォルダだけをcppcheckに指定することです。
cppcheck src/a src/b
src/a と src/b 以下の全てのファイルだけをチェックします。
第二の方法は、-iオプションと共に除外したいファイルやフォルダを指定することです。次のコマンドではsrc/c以下のファイルをチェックしません。
cppcheck -isrc/c src
インクルードパス指定
インクルードパスを追加するには-Iオプションに続けてパスを指定します。
Cppcheckのプリプロセッサは基本的に他のプリプロセッサと同様にインクルードを扱います。しかし、その他のプリプロセッサはヘッダファイルが見つからない場合に停止するのとは違って、cppcheckはただ単に、メッセージ情報を表示してソースコードの解析を続けます。
cppcheckは常にソースコード全体を確認する必要がないので、このような仕様になっています。実際に、全てのインクルードパスを与えないことを推奨しています。もちろん、クラスのメンバーの実装を確認した上でクラスの宣言をCppcheckでチェックするのは有用ではありますが、標準ライブラリのヘッダーをCppcheckに確認させるのは有用ではありません。というのは、チェックにかかる時間が長くなり、あまりよくない結果が表示されるからです。そのような場合、.cfg ファイル (後述します)によってcppcheckに関数や型の実装の情報を提供する方がよいでしょう。
Severities(厳格度)
メッセージのseverities(厳格度)には次のものがあります。:
error
バグが検出されたときに使用します。
warning
防衛的プログラミングでバグを避けるための提案です。
style
コードの可読性の向上に関連した、スタイル関連の指摘(未使用関数、冗長なコードなど)
performance
コードの高速化のための提案。これらの提案は、一般的な知識に基づいたものでしかありません。このメッセージの修正によって計測できるほど処理速度が向上するかどうかはわかりません。
portability
移植性についての警告。64 bit CPUへの移植性。コンパイラ依存(独自拡張)ソースコードについての警告など。
information
設定上の問題設定を変更している間だけ有効にすることをお勧めします。
メッセージの表示
デフォルトではerrorのメッセージだけを表示します。--enableを使用すると他のチェックを有効にできます。
# warning のメッセージを有効にします。
cppcheck --enable=warning file.c
# performanceのメッセージを有効にします。
cppcheck --enable=performance file.c
# informationのメッセージを有効にします。
cppcheck --enable=information file.c
# 歴史的な理由により --enable=style を指定すると warning, performance,
# portability と styleのメッセージを有効にします。古いxml形式を使用しているときには、これらの厳格度を"style"として報告されます。
cppcheck --enable=style file.c
# warning と performance のメッセージを有効にします。
cppcheck --enable=warning,performance file.c
# unusedFunction のチェックを有効にします。今回は --enable=styleでは有効にできない。
# というのは、これではライブラリではうまく動作しないからです。
cppcheck --enable=unusedFunction file.c
# 全てのメッセージを有効にします。
cppcheck --enable=all
--enable=unusedFunctionはプログラム全体をチェックするときにだけ有効にしてください。また、--enable=allもプログラム全体をチェックするときにだけ有効にしてください。というのは、unusedFunction チェックは、関数が呼び出されなかったときに警告するチェックだからです。関数呼び出しがチェック範囲にみつからなかったという可能性のノイズになります。
疑いのあるチェック
Cppcheckはデフォルトで解析に疑いのない場合にだけエラーメッセージを表示します。しかし、--inconclusiveオプションを使用すると、解析に疑いのある場合であってもエラーメッセージを表示します。
cppcheck --inconclusive path
これは、もちろん、実際に問題がないものに対しても、警告することになります。このオプションは、疑いのある警告を表示してもよい場合に限り、使用してください。
結果をファイルに保存
多くの場合、チェックの結果をファイルに保存したいと考えるでしょう。通常のシェルのリダイレクション機能を使って、エラー出力をファイルに保存することができます。
cppcheck file1.c 2> err.txt
マルチスレッドチェック
オプションの-j を使用してスレッド数を指定することができます。例えば、4スレッドを使ってフォルダ以下の全てのファイルをチェックする場合は次のように実行します。
cppcheck -j 4 path
このチェックでは未使用関数の検出(unusedFunction checking)は無効になることに注意してください。
プラットフォーム
あなたがターゲットとするプラットフォームの設定を使用すべきです。
デフォルトで、Cppcheckはネイティブのプラットフォームの設定を使用しますので、あなたのソースコードがローカルの環境でコンパイルし実行する場合には正常に動作するでしょう。
Cppcheck にはビルトインのプラットフォーム設定として、unixとwindowsをターゲットにしたものがあります。コマンドラインオプションの--platformを使ってプラットフォーム設定を指定できます。
XMLファイルで自身のプラットフォームにあった設定ファイルを作成することもできます。ここに例をあげます。:
<?xml version="1"?>
<platform>
<char_bit>8</char_bit>
<default-sign>signed</default-sign>
<sizeof>
<short>2</short>
<int>4</int>
<long>4</long>
<long-long>8</long-long>
<float>4</float>
<double>8</double>
<long-double>12</long-double>
<pointer>4</pointer>
<size_t>4</size_t>
<wchar_t>2</wchar_t>
</sizeof>
</platform>
プリプロセッサの設定
Cppcheckはデフォルトでプリプロセッサのデファインのコンパイルスイッチ設定の組み合わせを全てチェックします。(ただし、これらのうち #error を除く)
これを変更するには -D を使います。また -D を使用した場合、cppcheckは与えられたコンパイルスイッチだけが有効でその他は設定されていないとしてチェックします。これは、コンパイラのように動作します。また、 --force や --max-configs を使用すると、コンパイルスイッチの組み合わせの上限を上書きしてチェックすることができます。
# 全てのコンパイルスイッチの組み合わせをチェックする。
cppcheck file.c
# Aのコンパイルスイッチが有効になっている場合の組み合わせをチェックする
cppcheck -DA file.c
# check all configurations when macro A is defined
cppcheck -DA --force file.c
また、もう一つのオプションに-U があります。これはシンボルのundefとなります。使用例:
cppcheck -UX file.c
これはXが定義されていないことを意味します。Cppcheck は Xが定義されている組み合わせをチェックしません。
XML出力
Cppcheckは出力をXML形式に変更できます。XML出力には古いXML 形式(version 1) と新しいXML 形式(version 2)があります。可能であれば、新しい形式をご利用ください。
古い形式は後方互換性のためだけに残してあります。現在、変更の予定はありませんが、いつかは古い形式をサポートしなくなります。--xml オプションでフォーマットを指定します。
新しい形式は古い形式にあったいくつかの問題を解消しています。新しい形式も、おそらくいつかは、新しい属性や要素を追加するなど変更されるかもしれません。Cppcheckでファイルをチェックし、新しいXML形式で出力するコマンドのサンプルです。:
cppcheck --xml-version=2 file1.cpp
ここにバージョン2の出力の例を挙げます。:
<?xml version="1.0" encoding="UTF-8"?>
<results version="2">
<cppcheck version="1.66">
<errors>
<error id="someError" severity="error" msg="short error text"
verbose="long error text" inconclusive="true" cwe="312">
<location file="file.c" line="1"/>
</error>
</errors>
</results>
<error> 要素
それぞれのエラーは<error>要素に記載されます。属性:
id
エラーのidこれは、妥当なシンボル名です。
severity
以下のいずれかです: error, warning, style, performance, portability, information
msg
短い形式のエラーメッセージ
verbose
長い形式のエラーメッセージ
inconclusive
この属性は、メッセージに疑いのある場合にのみ使用されます。
cwe
メッセージのCWE ID。こ属性は、メッセージのCWE IDが判明している場合のみ使用されます。
<location>要素
エラーに関連する全ての位置情報は<location> 要素内にリストアップされます。主要な位置は、リストの最初の要素になります。
属性:
file
ファイル名相対パスまたは絶対パスのどちらかです。
line
数
msg
この属性は使用しません。ただし将来のいつか、それぞれの位置に短いメッセージを追加するようになるかもしれません。
出力の形式の変更
もし、テンプレートを使用して、出力の形式を変更することができます。
Visual Studioに互換性のある形式が必要な場合には、--template=vsを使用します。
cppcheck --template=vs gui/test.cpp
このオプションは出力形式を次のように変更します。:
Checking gui/test.cpp...
gui/test.cpp(31): error: Memory leak: b
gui/test.cpp(16): error: Mismatching allocation and deallocation: k
gcc に互換性のある形式が必要な場合には、--template=gccを使用します。:
cppcheck --template=gcc gui/test.cpp
このオプションは出力形式を次のように変更します。:
Checking gui/test.cpp...
gui/test.cpp:31: error: Memory leak: b
gui/test.cpp:16: error: Mismatching allocation and deallocation: k
それ以外に、自分自身の作成したパターンで指定することもできます。例としてコンマ区切りで出力してみましょう。:
cppcheck --template="{file},{line},{severity},{id},{message}" gui/test.cpp
このオプションは出力形式を次のように変更します。:
Checking gui/test.cpp...
gui/test.cpp,31,error,memleak,Memory leak: b
gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocation: k
以下のようなフォーマット指定項目がサポートされています。
callstack
callstack ただし可能な場合に限る。
file
ファイル名
id
メッセージid
line
行数
message
長い形式のメッセージ
severity
メッセージの種類、レベル
その他エスケープシーケンス \b (バックスペース), \n (改行), \r (改ページ) , \t (タブ) がサポートされています。
出力の抑制
ある種のエラーをフィルタリングしたい場合、出力を抑制することができます。
エラー種による出力の抑制
エラーの種類によって出力を抑制することができます。つぎのいずれかの形式で出力を抑制します。:
[error id]:[filename]:[line]
[error id]:[filename2]
[error id]
このerror id は抑制したいエラーのidです。このエラーのIDを簡単に調べるには、--xmlオプションをコマンドラインで与えます。そのXML出力から、idの文字列が取得できます。このエラーのIDに*を指定して全ての種類のメッセージを抑制することができます。(これは指定したファイルに限ることができます。)
またfilenameにはワイルドキャラクターである、* または ?を含めることができます。前者には全ての文字列にマッチし、後者は任意の一文字にマッチします。またWindowsを含む全てのOSで、パス区切りに"/" を使うことをお勧めします。
コマンドライン抑制
--suppress=のコマンドラインオプションを使用して、コマンドラインで抑制を指定することができます。例:
cppcheck --suppress=memleak:src/file1.cpp src/
ファイルで抑制リストを指定
また、抑制ファイルを作成することもできます。例:
// src/file1.cppのmemleak と exceptNew の エラーを抑制
memleak:src/file1.cpp
exceptNew:src/file1.cpp
// 全てのファイルのuninitvarエラーを抑制する。
uninitvar
空行やコメント行を抑制ファイルに記載することができます。
そして、この抑制ファイルは次のようにして使用します。:
cppcheck --suppressions-list=suppressions.txt src/
インライン出力抑制
エラー出力の抑制をソースコーオ中に直接、コメントの形で記載することもできます。このコメントには特別なキーワードを含めて記載します。ただし、インライン出力を抑制するコメントをソースコードに追加すると、ソースコードの可読性が少し悪くなってしまうかもしれません。
このソースコードは通常エラメッセージを出力する例です。:
void f() {
char arr[5];
arr[10] = 0;
}
前のソースコードに対する出力は次のようになります。:
# cppcheck test.c
Checking test.c...
[test.c:3]: (error) Array 'arr[5]' index 10 out of bounds
このエラーメッセージを抑制するには次のようなコメントを追加します。:
void f() {
char arr[5];
// cppcheck-suppress arrayIndexOutOfBounds
arr[10] = 0;
}
これで、--inline-suppr オプションの準備ができました。次のようにcppcheckを起動するとエラーが抑制されます。:
cppcheck --inline-suppr test.c
ライブラリ設定
windows, posix, gtk, qt,他の外部のライブラリを使用した場合、Cppcheckは外部の関数がどのようなものであるかがわかりません。Cppcheck はそのため、メモリリークやバッファオーバーフロー、ヌルポインタのデリファレンスの可能性といったさまざまな問題が検出できません。これを解決するには設定ファイル(.cfg file)を使用します。
もしあなたが有名なライブラリの設定ファイルを作成したときには、私達のサイトにアップロードしてくれると非常に助かります。
カスタム設定ファイル(.cfg file)の使用
あなたのプロジェクト専用の設定ファイルを作成し、使用することができます。そのためには、--check-library と--enable=information を使用して設定のためのヒントを入手します。
コマンドラインのcppcheck はカスタマイズした設定ファイル(.cfg files)を作業パスから読み込もうとします。作業パスはcppcheckを実行しているパスですでそこに設定ファイルがあると考えます。
GUIのcppcheckはプロジェクトのファイルパスから設定ファイルを読み込もうとします。カスタマイズした設定ファイル(.cfg file)は プロジェクトファイルの編集 ダイアログで確認できます。このタイアログを表示させるにはファイル メニューから開いてください。
メモリーリソースのリーク
Cppcheck はリークのチェックについての設定できます。
alloc と dealloc
ここにサンプルのプログラムがあります。:
void test()
{
HPEN pen = CreatePen(PS_SOLID, 1, RGB(255,0,0));
}
このサンプルには、リーソースのリークがあります。CreatePen()はWindowsの関数でpenを作成します。しかし、Cppcheck はこの関数が返す値を解放しなければならないことがわかりません。そのためエラーメッセージは表示されません。:
# cppcheck pen1.c
Checking pen1.c...
もし、windowsの設定ファイルをCppcheckに提供すれば、この問題を指摘することができるようになります。:
# cppcheck --library=windows.cfg pen1.c
Checking pen1.c...
[pen1.c:3]: (error) Resource leak: pen
これが最小限のwindows.cfg ファイルです:
<?xml version="1.0"?>
<def>
<resource>
<alloc>CreatePen</alloc>
<dealloc>DeleteObject</dealloc>
</resource>
</def>
leak-ignore とuse
しばしば、割り当てられたポインタを関数に渡すことがあります。例:
void test()
{
char *p = malloc(100);
dostuff(p);
}
もし設定ファイルがなく、Cppcheckがdostuffの仕様を把握していなければ、Cppcheckはdostuffがメモリーについて配慮しており、メモリーリークは発生しないと仮定します。
dostuffがメモリーについて配慮せず、解放などを行なっていないことを指定するためには、leak-ignoreを使用します。:
<?xml version="1.0"?>
<def>
<function name="dostuff">
<leak-ignore/>
<arg nr="1"/>
<arg nr="2"/>
</function>
</def>
これとは逆にdostuffがメモリーについて配慮している場合には次のように設定します。:
<?xml version="1.0"?>
<def>
<memory>
<alloc>malloc</alloc>
<dealloc>free</dealloc>
<use>dostuff</use>
</memory>
</def>
なお、この<use>設定には論理的には全く無意味です。この設定がない場合でも同じエラーが表示されます。これは--check-libraryのinformationメッセージを減らすために使用します。
関数引数: 未初期化メモリ
ここにサンプルのプログラムがあります。:
void test()
{
char buffer1[1024];
char buffer2[1024];
CopyMemory(buffer1, buffer2, 1024);
}
このプログラムのバグは buffer2 が初期化されていないことです。CopyMemory 関数の第二引数は初期化されている必要があります。しかし、Cppcheckは関数に未初期化の変数を渡してもよいと仮定しています。:
# cppcheck uninit.c
Checking uninit.c...
もし、windowsの設定ファイルをCppcheckに提供すれば、この問題を指摘することができるようになります。:
# cppcheck --library=windows.cfg uninit.c
Checking uninit.c...
[uninit.c:5]: (error) Uninitialized variable: buffer2
これが最小限のwindows.cfgファイルです。:
<?xml version="1.0"?>
<def>
<function name="CopyMemory">
<arg nr="1"/>
<arg nr="2">
<not-uninit/>
</arg>
<arg nr="3"/>
</function>
</def>
関数引数: ヌルポインタ
Cppcheckは、関数にヌルポインタを渡してもよいと仮定しています。ここにサンプルのプログラムがあります。:
void test()
{
CopyMemory(NULL, NULL, 1024);
}
MSDNの文書はこれが問題あるかないかを明らかにしていません。しかし、ここでは問題ありと仮定します。Cppcheck は関数にヌルポインタを渡してもよいと仮定していますので、エラーを出力しません。:
# cppcheck null.c
Checking null.c...
もし、windowsの設定ファイルをCppcheckに提供すれば、この問題を指摘することができるようになります。:
cppcheck --library=windows.cfg null.c
Checking null.c...
[null.c:3]: (error) Null pointer dereference
これが最小限のwindows.cfg ファイルです:
<?xml version="1.0"?>
<def>
<function name="CopyMemory">
<arg nr="1">
<not-null/>
</arg>
<arg nr="2"/>
<arg nr="3"/>
</function>
</def>
関数引数: フォーマット文字列
フォーマット文字列を扱う関数を定義できます。例:
void test()
{
do_something("%i %i\n", 1024);
}
これについてもエラーは報告されません。:
# cppcheck formatstring.c
Checking formatstring.c...
引数がフォーマット文字列であることを出力する設定ファイルが作成できます。設定ファイルの例です。:
<?xml version="1.0"?>
<def>
<function name="do_something">
<formatstr type="printf"/>
<arg nr="1">
<formatstr/>
</arg>
</function>
</def>これで、Cppcheckはエラーを報告することができるようになりました。:
cppcheck --library=test.cfg formatstring.c
Checking formatstring.c...
[formatstring.c:3]: (error) do_something format string requires 2 parameters but only 1 is given.
このフォーマット文字列のtype属性は次のどちらかになります。:
printf - printf のルールに従うフォーマット文字列
scanf - scanf のルールに従うフォーマット文字列
関数引数: 値の範囲
有効な値の範囲が定義できます。想像してください。:
void test()
{
do_something(1024);
}
これについてもエラーは報告されません。:
# cppcheck valuerange.c
Checking valuerange.c...
1024 が 範囲外の値であることを出力する設定ファイルが作成できます。設定ファイルの例です。:
<?xml version="1.0"?>
<def>
<function name="do_something">
<arg nr="1">
<valid>0:1023</valid>
</arg>
</function>
</def>これで、Cppcheckはエラーを報告することができるようになりました。:
cppcheck --library=test.cfg range.c
Checking range.c...
[range.c:3]: (error) Invalid do_something() argument nr 1. The value is 1024 but the valid values are '0-1023'.
validの要素で次のような表現が利用できます。:
0,3,5 => 0, 3 それに 5 だけが有効な値です。
-10:20 => -10 から 20 までの値(両端含む)が有効な値です。
:0 => 0または0未満の値が有効な値です。
0: => 0または0以上の値が有効な値です。
0,2:32 => 0 または2から32までの値(両端含む)が有効な値です。
関数引数: 最小サイズ
いくつかの関数はバッファーを引数にとります。バッファの最小サイズを指定することができます。(要素数ではなくバイト数です。)想像してください。:
void test()
{
char str[5];
do_something(str,"12345");
}
これについてもエラーは報告されません。:
# cppcheck minsize.c
Checking minsize.c...
設定ファイルで、例えば、引数1のバッファのサイズが引数2の文字列長より大きくなればならないと警告するような設定ファイルを作成できます。例を挙げます。:
<?xml version="1.0"?>
<def>
<function name="do_something">
<arg nr="1">
<minsize type="strlen" arg="2"/>
</arg>
<arg nr="2"/>
</function>
</def>これで、Cppcheckはこのエラーを報告することができるようになりました。:
cppcheck --library=1.cfg minsize.c
Checking minsize.c...
[minsize.c:4]: (error) Buffer is accessed out of bounds: str
minsizes はいくつかの種類があります。:
strlen
バッファーのサイズが、その他の引数の文字列長より大きくなければなりません。例: std.cfg のstrcpyの設定を参照してください。
argvalue
バッファーのサイズがその他の引数の値より大きくなればなりません。例: std.cfg のmemsetの設定を参照してください。
sizeof
バッファーのサイズがその他の引数のバッファーのサイズより大きくなればなりません。例: std.cfg のstrcnpyの設定を参照してください
mul
バッファーのサイズがその他の2つの引数の値の積より大きくなればなりません。典型的な使用例としては、一つの引数が構造体などの要素のサイズを指定し、もうひとつの引数が要素の個数を定義するような場合です。例: std.cfg のfreadの設定を参照してください
noreturn
Cppcheck はこの関数がいつも値を返すとは仮定していません。ここにサンプルのプログラムがあります。:
void test(int x)
{
int data, buffer[1024];
if (x == 1)
data = 123;
else
ZeroMemory(buffer, sizeof(buffer));
buffer[0] = data; // <- error: xが1でないとき初期化されていない
}
理屈の上では、ZeroMemoryがプログラムを終了させてもバグはありません。そのため Cppcheckはエラーを報告しません。:
# cppcheck noreturn.c
Checking noreturn.c...
しかし、--check-library と--enable=informationをつかうとエラーが出力されます。:
# cppcheck --check-library --enable=information noreturn.c
Checking noreturn.c...
[noreturn.c:7]: (information) --check-library: Function ZeroMemory() should have <noreturn> configuration
もし適切な windows.cfg が提供されていましたら、このバグは検出されます。:
# cppcheck --library=windows.cfg noreturn.c
Checking noreturn.c...
[noreturn.c:8]: (error) Uninitialized variable: data
これが最小限のwindows.cfg ファイルです:
<?xml version="1.0"?>
<def>
<function name="ZeroMemory">
<noreturn>false</noreturn>
</function>
</def>
use-retval
他になにも指定されていない限り、cppcheckは関数が返り値を無視していても問題ないと仮定します。:
bool test(const char* a, const char* b)
{
strcmp(a, b); // <- bug: strcmp の呼び出しは副作用を持ちませんが返り値を無視している。
return true;
}
strcmp が副作用を持つ場合、パラメータが関数に渡されている結果を無視しても問題はなく、このような仮定は正しいといえます。:
# cppcheck useretval.c
Checking useretval.c...
もし適切なlib.cfg が提供されていましたら、このバグは検出されます。:
# cppcheck --library=lib.cfg --enable=warning useretval.c
Checking useretval.c...
[noreturn.c:3]: (warning) Return value of function strcmp() is not used.
これが最小限のlib.cfg ファイルです。:
<?xml version="1.0"?>
<def>
<function name="strcmp">
<use-retval/>
</function>
</def>
define
ライブラリはマクロプリプロセッサのdefineを使用することができます。例:
<?xml version="1.0"?>
<def>
<define name="NULL_VALUE" value="0"/>
</def>
プリプロセッサの段階でソースコード中に "NULL_VALUE" が現れるごとに、"0"で置き換えます。
podtype
多くのソースコードで、プラットフォームに依存しない型をtypedefによって定義しています。"podtype"のタグによって、cppcheckがこれらのサポートするために必要な情報を提供できます。このような情報のない場合、cppcheckは次の例でみるような "uint16_t" 型を理解できません。
void test() {
uint16_t a;
}
そのため、未使用変数である、'a'が未使用であるとのメッセージが表示されません。
# cppcheck --enable=style unusedvar.cpp
Checking unusedvar.cpp...
もし uint16_t が以下のように定義されていた場合、結果にメッセージが反映されます。
<?xml version="1.0"?>
<def>
<podtype name="uint16_t" sign="u" size="2"/>
</def>
型のサイズはバイトサイズで指定します。符号の "sign" 属性は 符号ありの "s" か 符号無し "u" のどちらかです。これらの属性はオプションです。このライブラリを使用しますと、cppcheckはメッセージを表示できるようになります。
# cppcheck --library=lib.cfg --enable=style unusedvar.cpp
Checking unusedvar.cpp...
[unusedvar.cpp:2]: (style) Unused variable: a
container
C++ ライブラリの多くや STL 自身は、非常によく似た機能性をもつコンテナを提供する。ライブラリによってその動作をcppcheckに伝えることができる。それぞれのコンテナの設定にはユニークなIDが必要とします。コンテナの設定には、startPatternを加えることができます(オプション)。この startPatternはToken::Match パターンとendPattern に有効でなけばなりません。また、このendPatternはリンクしているトークンと比較されるものです。オブション属性の"inherits"は事前に定義されたコンテナのIDをとります。
<container>タグの内部で、<size>、<access>、<other>を選択して使用して関数を定義できます。これらのタグはそれぞれ、"resize" やその結果を与えるような動作を指定することができます。その例 "end-iterator"を示します。
次の例は、std::vectorの為の定義を示しています。std::vectorは"stdContainer"の定義に基づいていますが、ここには表示していません。:
<?xml version="1.0"?>
<def>
<container id="stdVector" startPattern="std :: vector <" inherits="stdContainer">
<size>
<function name="push_back" action="push"/>
<function name="pop_back" action="pop"/>
</size>
<access indexOperator="array-like">
<function name="at" yields="at_index"/>
<function name="front" yields="item"/>
<function name="back" yields="item"/>
</access>
</container>
</def>
関数strcpyの設定例
標準関数のstrcpyのための適切な設定は次のようになる。:
<function name="strcpy">
<leak-ignore/>
<noreturn>false</noreturn>
<arg nr="1">
<not-null/>
</arg>
<arg nr="2">
<not-null/>
<not-uninit/>
<strz/>
</arg>
</function>
この<leak-ignore/> は、リークチェック中に関数呼び出しを無視するように、Cppcheckに伝えます。この関数は、割り当てられたメモリを解放しないことを意味しています。
この<noreturn> は、この関数が、返り値を返すかどうかをCppchecに伝えます。
この関数は第一引数にポインタを取ります。しかしこのポインタは、ヌルポインタであってはなりません。というのは<not-null>が使用されているからです。
この関数は第二引数にポインタを取ります。このポインタはヌルポインタであってはなりません。また、このポインタは初期化されたデータを指していなければなりません。<not-null> と <not-uninit> は正しく使用されています。さらにいえば、このポインタは0終端文字列(zero-terminated string)でなければなりません。そのため<strz>が使用されています。
全ての引数に対する指定
引数の数に -1を指定すると、チェック時にその関数の全ての引数に適用されます。それぞれの引数に対する設定は、全ての引数に対する指定を上書きします。
ルール(Rules)
正規表現を使用して、ユーザーがルール(rule)を定義することができます。
これらのカスタムルールは、ソースコードを高度に分析した結果を使用することができません。しかしソースコード中の非常にシンプルなパターンについて簡単にルールを作成することができます。
ルールの作成を始めるには次の関連記事を参照してください。:
http://sourceforge.net/projects/cppcheck/files/Articles/
ルールのファイルフォーマットは次のとおりです。:
<?xml version="1.0"?>
<rule>
<tokenlist>LIST</tokenlist>
<pattern>PATTERN</pattern>
<message>
<id>ID</id>
<severity>SEVERITY</severity>
<summary>SUMMARY</summary>
</message>
</rule>
patternタグ中にCDATAを含めた場合、XMLに干渉する可能性がありますので使用時はご注意ください。:
<![CDATA[some<strange>pattern]]>
<tokenlist>
この<tokenlist> 要素はオプションです。この要素がある場合、どのトークンをチェックするかを指示することができます。このLISTはdefine, raw, normal , simpleのいずれかです。
define
#define プリプロセッサの記述をチェックするために使用します。
raw
プリプロセッサの出力をチェックするために使用します。
normal
normal のトークンリストをチェックするために使用します。ソースコードをある程度、単純化した結果をチェックすることになります。
simple
単純なトークンリストをチェックするために使用します。ソースコードを完全に単純化した結果をチェックすることになります。ほとんどの Cppcheckのチェックには、この 単純ばトークンリストを使用します。
もし<tokenlist>要素を省略した場合、simple が使用されます。
<pattern>
このPATTERN にはPerlの正規表現と互換性のある正規表現 PCREを指定します。
<id>
この ID にはユーザーが定義した message idを指定します。
<severity>
このSEVERITYにはCppcheck の厳格度(severities)である、次のいずれかを指定します。: information, performance, portability, style, warning,error
<summary>
オプションです。メッセージのサマリーです。もしこのsummaryトークンが指定されていなければ、マッチしたトークンが出力されます。
Cppcheck アドオン
Cppcheckのアドオンは、個別のスクリプトや個別のプログラムとして実装されています。Cppcheckのアドオンを使用すると次のような利点があります。
洗練された分析の結果を使用した個別の、外部チェックを追加できます。
ソースコードが可視化できます。
その他
Cppcheckアドオンの使用方法
現在、アドオンを使用するには2段階の操作が必要です。:
Cppcheckを実行し、ダンプファイルを生成します。
アドオンでダンプファイルを処理します。
--dumpフラグを使用するとダンプファイルを生成できます。foo/ フォルダ以下の全てのソースファイルからダンプファイルを生成するには次のようにします。
cppcheck --dump foo/
foo/ フォルダ以下の全てのダンプファイルをアドオンで処理するには次のようにします。
python addon.py foo/*.dump
Cppcheckアドオンの見つけ方
ダウンロードできる、アドオンがいくつかあります。
Cppcheck プロジェクトはいくつかのアドオンを以下の場所で提供しています。: http://github.com/danmar/cppcheck/blob/master/addons
ublinterは規格で定義されていない未定義動作に注力した"lint"です。: http://github.com/danmar/ublinter
あなたのアドオンの情報をご紹介ください。(商用、フリーを問いません。)
Cppcheck アドオンの作成
Cppcheck は XML形式でダンプファイルを生成できます。このファイルには以下のようなものが含まれています。:
トークンリスト(Token list)
シンタックスツリー(Syntax trees)
シンボルデータベース(関数、クラス、変数、スコープ)
既知の値(value flow analysis)
Cppcheckはアドオンを直接実行することはできません。直接実行するためにインターフェースはありません。これは、次のような制限がないことを意味します。:
アドオンを作成しリリースする際に、どのようなライセンスでも適用できます。
アドオンの作成に、どのようなスクリプト言語やプログラミング言語で作成できます。
アドオン作成者がユーザーインターフェースと出力を決定できます。
警告の生成以外の目的にもアドオン使用できます。
アドオン作成者の利便性のために、Cppcheck プロジェクトは PythonからCppcheckのデータにアクセスするための cppcheckdata.pyを提供しています。cppcheckdata.pyの使用はオプションです。
使用例1 - 全トークンの表示
Script:
import sys
import cppcheckdata
def printtokens(data):
for token in data.tokenlist:
print(token.str)
for arg in sys.argv[1:]:
printtokens(cppcheckdata.parse(arg))
使用例2 - 全関数リストアップ
Script:
import sys
import cppcheckdata
def printfunctions(data):
for scope in data.scopes:
if scope.type == 'Function':
print(scope.className)
for arg in sys.argv[1:]:
printfunctions(cppcheckdata.parse(arg))
使用例 3 - 全クラスリストアップ
Script:
import sys
import cppcheckdata
def printclasses(data):
for scope in data.scopes:
if scope.type == 'Class':
print(scope.className)
for arg in sys.argv[1:]:
printfunctions(cppcheckdata.parse(arg))
HTML 形式での報告
cppcheckのXML出力をHTML形式に変更できます。これを利用するには、Python と pygments module (http://pygments.org/) が必要です。Cppcheckのソースツリーにhtmlreportというフォルダがあります。このフォルダには、CppcheckのXMLファイルをHTML出力に変換するスクリプトがあります。
このコマンドでヘルプ画面を生成するには次のように実行します。
htmlreport/cppcheck-htmlreport -h
出力画面には次の内容が表示されます。:
Usage: cppcheck-htmlreport [options]
Options:
-h, --help show this help message and exit
--file=FILE The cppcheck xml output file to read defects from.
Default is reading from stdin.
--report-dir=REPORT_DIR
The directory where the html report content is written.
--source-dir=SOURCE_DIR
Base directory where source code files can be found.
使用例:
./cppcheck gui/test.cpp --xml 2> err.xml
htmlreport/cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=.
グラフィカルインターフェースGUI
イントロダクション
Cppcheck GUIが利用できます。
メイン画面は、このソフトを起動時に表示されます。
ソースコードのチェック
Checkメニューを使用します。
結果の確認
結果はリスト表示されます。
View メニューを操作して、メッセージの種類毎に表示/非表示を切り替えできます。
結果をXML ファイルに保存して、後で確認できます。Save results to file と Open XMLを参照してください。
設定
Languageメニューからいつでも使用言語を変更できます。
設定は、 Edit Preferences で変更できます。
プロジェクトファイル
プロジェクトファイルは、プロジェクト固有の設定を保存するのに使用します。固有の設定には次のものがあります。:
インクルードパス
プリプロセッサのdefine
このマニュアルの3 章にあるように、全てのコンパイルスイッチの組み合わせをチェックします。コンパイルスイッチの組み合わせを制限したい場合にだけ、プリプロセッサのdefineを指定してください。