Third Degree ツールは,C および C++ プログラムにおけるヒープ・メモリのリーク,無効アドレスの参照,および初期化されていないメモリの読み込みを検査します。
始めに,-g
または
-g
n
オプションを使用してプログラムをコンパイルしておく必要があります (n
は 0 より大きな値)。
また,Third Degree は,ヒープ・オブジェクトのリストを作成し,浪費されているメモリを検出するので,プログラムの割り当てパターンの決定にも役立ちます。
これは,メモリ管理サービスを自動的に監視し,実行時に命令をロード/格納するための追加のコードで,実行可能オブジェクトを計測することによって行われます。
要求されたレポートは,オプションで表示できる 1
つまたは複数のログ・ファイルに書き込まれるか,
xemacs
(1)
Third Degree は,省略時の設定ではメモリ・リークのみを検査するため,計測および実行時分析を短時間で行うことができます。
費用がかかり,処理のじゃまになるその他の検査は,コマンド行のオプションで選択します。
詳細については,
third
(1)
Third Degree は,次のタイプのアプリケーションに使用できます。
malloc
,calloc
,realloc
,valloc
,alloca
,sbrk
の各関数,および C++ の
new
関数を使用してメモリを割り当てるアプリケーション。
Third Degree を使用して,mmap
関数など,他のメモリ割り当て機能を使用するプログラムも計測できますが,この方法で取得したメモリへのアクセスは検査しません。
アプリケーションが
mmap
を使用する場合は,
third
(1)
Third Degree は
brk
関数への呼び出しを検出して,禁止します。
さらに,プログラムが,sbrk
関数を使用して取得した大きなブロックを分割することによってメモリを割り当てる場合,Third Degree は,エラーが発生したメモリ・ブロックを厳密に特定できないことがあります。
fork
(2)
third
(1)-fork
オプションを指定する必要があります。
POSIX スレッド
(
pthread
(3)
third
(1)-pthread
オプションを指定する必要があります。
pthread
プログラムでは,Third Degree は,無効なアドレスまたは初期化されていない変数にアクセスする際に,システム・ライブラリ・ルーチン (libc
,libpthread
など) を検査しません。
したがって,strcpy
およびその他のルーチンも検査されません。
31 ビットのヒープ・アドレスを使用するアプリケーション。
7.1 アプリケーションにおける Third Degree の実行
Third Degree を起動するには,次のように
third
(1)
third
[option...]
app
[argument...]
このコマンド形式では,option
には,省略時のスレッドを使用しないリーク検査以外に 1 つまたは複数のオプションを選択します。
app
は,アプリケーションの名前です。
argument
は,計測機構付きプログラムをすぐに実行したい場合にアプリケーションに渡される 1 つまたは複数のオプションの引数を表します (app
が引数を必要としない場合は,-run
オプションを使用します)。
app.third
(
third
(1)
計測コードが追加で挿入されたため,コードが大きくなり,実行速度は遅くなります。 オーバヘッドの大きさは指定されたオプションの数と性質によって異なります。
初期化されていないデータの誤使用を検出するために,Third Degree は,アプリケーションで初期化されないデータをすべて特殊なパターン (0xfff8a5a5,または
-uninit
オプションで指定されたパターン) で初期化します。
これにより,計測機構付きプログラムの動作が変わったり,誤動作したり,またはクラッシュしたりすることがあります (特に,この特別なパターンがポインタとして使用される場合)。
これらの動作はすべて,プログラムにバグがあることを示しています。
これは,計測機構付きプログラムで回帰テストを行う際に活用できます。
また,
third
(1)-g
オプションを使用してデバッガを実行すると,問題を調査することができます。
Third Degree は,-uninit
オプションが指定された場合 (-uninit heap+stack
など) にのみ,このようにメモリに特殊なパターンで埋め込みを行います。
それ以外の場合,ほとんどの計測機構付きプログラムは,元のプログラムと同様に動作します。
Third Degree は,境界チェックができるようにするために,割り当てられた各ヒープ・メモリ・オブジェクトに埋め込みを行っているので,それらのオブジェクトが大きくなっています。
埋め込みの量は,-pad
オプションを指定することによって調整できます。
free
または
delete
を使用してメモリを解放する場合,不正なアクセスを検出するため,空きプールによって阻止されます。
これは,です。
-free
オプションを使用して,待機時間を調節します。
Third Degree のエラー・メッセージの記述形式は,C コンパイラが使用する記述形式と類似しています。
省略時の設定では,Third Degree は,app.3log
という名前のログ・ファイルにエラー・メッセージを書き込みます。
emacs
を使用すると,各エラーを自動的に順番に指定することができます。
emacs
では,[Esc/X]
compile
を使用して,省略時の
make
コマンドを
cat
app.3log
などのコマンドに置き換え,[Ctrl/X]
`
を使用して,コンパイル・エラーの場合のように,順番にエラーを表示していきます。
ログ・ファイルに使用される名前は,次のオプションのうちいずれかを指定することによって変更できます。
-pids
プロセス識別番号 (PID) をログ・ファイル名に含めます。
-dirname
directory-name
Third Degree がそのログ・ファイルを作成するディレクトリ・パスを指定します。
-fork
フォークした各プロセスのログ・ファイル名に PID を含めます。
使用するオプションによって,ログ・ファイル名は次のようになります。
オプション | ファイル名 | 使用 |
なし,または
-fork
parent |
app.3log |
省略時の設定 |
-pids
または
-fork
child |
app.12345.3log |
PID を取り込む |
-dirname /tmp |
/tmp/app.3log |
ディレクトリを設定 |
-dirname /tmp -pids |
/tmp/app.12345.3log |
ディレクトリと PID を設定 |
シグナル・ハンドラでのエラーは,追加の
.sig.3log
オプションにより通知されます。
7.1.1 シェアード・ライブラリでの Third Degree の使用
strcpy
関数に渡すバッファが小さすぎるなど,アプリケーション内のエラーは,ライブラリ・ルーチンで見つかることがよくあります。
Third Degree はシェアード・ライブラリの計測をサポートしており,-non_shared
または
-call_shared
オプションを指定してリンクされたプログラムを計測します。
次のオプションを指定すると,Third Degree が計測するシェアード・ライブラリを決定できます。
-all
呼び出し共用実行可能プログラムにリンクされたすべてのシェアード・ライブラリを計測します。
-excobj
objname
指定したシェアード・ライブラリを計測から除外します。
-excobj
オプションを複数回使用すれば,複数のシェアード・ライブラリを指定できます。
-incobj
objname
指定したシェアード・ライブラリを計測します。
-incobj
オプションを複数回使用すれば,dlopen()
を使用してロードしたシェアード・ライブラリを含め,複数のシェアード・ライブラリを指定できます。
-Ldirectory
リンカやローダが認識する通常の位置にプログラムのシェアード・ライブラリがない場合,Third Degree にその検索位置を通知します。
Third Degree がアプリケーションの計測を終了すると,現在のディレクトリには,指定した各シェアード・ライブラリの計測機構付きバージョンが含まれています。
また,必要に応じて
libc.so
,libcxx.so
,および
libpthread.so
の最低限の計測機構付きバージョンが作成されます。
計測機構付きアプリケーションは,ライブラリのこれらのバージョンを使用する必要があります。
LD_LIBRARY_PATH
環境変数を定義して,計測機構付きシェアード・ライブラリがどこに常駐するかを,計測機構付きアプリケーションに通知してください。
third
(1)-run
オプションを指定する場合,またはアプリケーションに引数を指定している場合にこれを自動的に行います。
また,計測機構付きプログラムを自動的に起動します。
省略時の設定では,Third Degree は,アプリケーションが使用するシェアード・ライブラリを完全には計測しません。
ただし,使用するときには,最低限
libc.so
,libcxx.so
,および
libpthread.so
を計測する必要があります。
これにより,計測の動作がはるかに高速になるとともに,計測機構付きアプリケーションも実行速度がより高速になります。
Third Degree は,通常,計測機構付き部分のエラーを検出して報告しますが,計測機構のないライブラリのエラーは検出しません。
部分的に計測したアプリケーションがクラッシュまたは誤動作し,Third Degree によって報告されたエラーをすべて修正した場合は,そのすべてのシェアード・ライブラリとともにアプリケーションを再計測し,新しい計測機構付きバージョンを実行するか,または Third Degree の
-g
オプションを使用してデバッガで問題を調査してください。
Third Degree は,プロシージャのスタック・トレースを含むエラー・レポートを生成するため,シェアード・ライブラリを計測する必要があります (ただし,省略時の設定では最小限のみ)。
また,デバッグ可能なプロシージャ (たとえば,-g
オプションを使用してコンパイルしたもの) は,エラーに最も近い最初のいくつかのスタック・フレーム内に表示される必要があります。
これにより,高度に最適化され,システム・ライブラリのアセンブリ・コードによって生成される可能性がある見せかけのエラーのプリントが回避されます。
この機能を無効にするには,-hide
オプションを使用してください。
pthread プログラムでは,Third Degree は,ある種のシステム・シェアード・ライブラリ (libc
を含む) のエラーを検査しません。
これは,そうした場合にスレッド・セーフでなくなるためです。
7.2 デバッグ例
次のソース・コード
ex.c
で表される小さなアプリケーションをデバッグしなければならないとします。
1 #include <assert.h> 2 3 int GetValue() { 4 int q; 5 int *r=&q; 6 return q; /* q is uninitialized */ 7 } 8 9 long* GetArray(int n) { 10 long* t = (long*) malloc(n * sizeof(long)); 11 t[0] = GetValue(); 12 t[0] = t[1]+1; /* t[1] is uninitialized */ 13 t[1] = -1; 14 t[n] = n; /* array bounds error*/ 15 if (n<10) free(t); /* may be a leak */ 16 return t; 17 } 18 19 main() { 20 long* t = GetArray(20); 21 t = GetArray(4); 22 free(t); /* already freed */ 23 exit(0); 24 }
以降の各項で,Third Degree を使用して,このサンプル・アプリケーションをデバッグする方法について説明します。
7.2.1 Third Degree のカスタマイズ
コマンド行オプションを使って,Third Degree のさまざまな機能のオン/オフを切り替えることができます。
オプションを何も指定しない場合,Third Degree はプログラムを次のように計測しますが,計測機構付きプログラムの実行や,生成される
.3log
ファイルの表示は行いません。
プログラム終了時にリーク検出を行う。
メモリ・エラー (無効なアドレスまたは初期化されていない値) を検査しない。
ヒープの使用履歴を分析しない。
計測機構付きアプリケーションは,LD_LIBRARY_PATH
環境変数の設定後に
./app.third
arg1 arg2
などのコマンドを使って実行できます。
また,アプリケーションの引数を
third
(1)-run
または
-display
オプションを指定したりすることもできます。
生成された
.3log
ファイルは,手動または
-display
オプションを指定することにより表示できます。
メモリ・エラー検査を追加するには,-invalid
オプションと
-uninit
オプションのいずれかまたは両方を指定します。
-invalid
オプションは,すべての
third
(1)-inv
) に短縮できます。
このオプションは,Third Degree に対し,重要なロードおよび格納命令のすべてが,アプリケーション・コードが使用すべき有効なメモリ・アドレスにアクセスしているかどうかを検査します。
このオプションを使用すると,目立った性能のオーバヘッドが生じますが,実行時環境にはほとんど影響を与えません。
-uninit
オプションには,キーワード引数を "+" で区切ってリストします。
これは,通常
heap+stack
(または
h+s
) となり,すべての重要なロード命令で,ヒープ・メモリとスタック・メモリの両方を検査するよう指示します。
検査には,malloc
など (calloc
ではなく) を使って割り当てられたすべてのスタック・フレームおよびヒープ・オブジェクトに,通常ではあり得ないパターン 0xfff8a5a5 を充填し,この値をメモリから読み取るすべてのロード命令を報告することが含まれます。
この場合,選択されたメモリは,初期化されていないデータ領域を読み取るコードを強調表示する点で,cc -trapuv
と同様に重大な問題があります。
問題を引き起こすコードが計測として選択されている場合,Third Degree はそれぞれの場合を
.3log
ファイル内で一度だけ報告します。
ただし,コードが計測されたかどうかに関係なく,コードは,元のプログラムがロードするはずの値の代わりに問題のあるパターンをロードおよび処理します。
この場合,パターンが有効なポインタ,文字,浮動小数点数ではなく,負の整数であるために,プログラムの誤動作またはクラッシュが引き起こされる場合があります。
このような動作は,プログラムにバグが含まれている印となります。
計測機構付きプログラム上で回帰テストを実行することにより,誤動作を識別できます。
third
(1)-quiet
を指定して,-display
を省略します。
.3log
ファイル内のエラー・メッセージを参照し,計測機構付きプログラムを,
dbx
(1)ladebug
(1)-g
オプションを付けてコンパイルし,
third
(1)-g
を指定します。
-uninit
オプションを指定すると,偽のエラー,特に変数,配列要素,32 ビット未満の構造体のメンバ (short
,char
ビットフィールドなど) がレポートされます。
詳細は,7.6 節を参照してください。
ただし,-uninit heap+stack
オプションを使用すると,リーク・レポートの正確性が向上します。
ヒープの使用分析を追加する場合は,-history
オプションを指定します。
これにより,-uninit heap
オプションが有効になります。
7.2.2 Makefile の変更
アプリケーションの makefile に,次のエントリを追加します。
ex.third: ex third ex
次のように
ex.third
を作成します。
> make ex.third third ex
ここで,計測機構付きアプリケーション
ex.third
を実行して,ログ
ex.3log
をチェックします。
あるいは,プログラム名の前に
-display
を追加すると,そのアプリケーションを実行して,.3log
ファイルが直ちに表示されます。
7.2.3 Third Degree のログ・ファイルの検査
ex.3log
ファイルには,以降の項で説明する部分がいくつか含まれています。
このコマンド行は,次のとおりであると想定します。
> third -invalid -uninit h+s -history -display ex
実行時に Third Degree が検出できるエラーのタイプには,初期化されていないメモリの読み取り,割り当てられていないメモリの読み取りまたは書き込み,誤ったメモリの解放,および例外を起こす可能性の高い一定の重大エラーなどの状態が含まれます。 各エラーに対して,次の項目を持つエラー・エントリが生成されます。
エラーのタイプと番号を記した見出し行
エラー見出し行には,各エラーの英字 3 文字の短縮形が表示されます (短縮形のリストについては,7.3 節を参照)。 エラーを引き起こしたプロセスがルート・プロセスではない場合 (たとえば,アプリケーションが 1 つまたは複数の子プロセスをフォークするため) は,エラーを引き起こしたプロセスの PID も見出し行に表示されます。
コンパイラのエラー・メッセージ行と似た書式のエラー・メッセージ
Third Degree は,ファイル名およびエラーが発生した位置に最も近い行番号をリストします。 通常,これは,エラーが発生した正確な位置ですが,エラーがライブラリ・ルーチン内で発生した場合は,ライブラリ・コールが行われた場所を示すこともあります。
1 つ以上のスタック・トレース
エラー・エントリの最後の部分はスタック・トレースです。 スタック・トレースにリストされる最初のプロシージャは,エラーが発生したプロシージャです。
次の例に,ログ・ファイルからのエントリを示します。
次のログ・エントリは,プロシージャ
GetValue
のローカル変数が,初期化される前に読み取られたことを示しています。
行番号が表示されるのは,q
に値が与えられなかったことを確認するためです。
---------------------------------------------------- rus -- 0 -- ex.c: 6: reading uninitialized local variable q of GetValue GetValue ex, ex.c, line 6 GetArray ex, ex.c, line 11 main ex, ex.c, line 20 __start ex
次のログ・エントリは,12 行目でエラーが発生したことを示しています。
t[0] = t[1]+1
配列が初期化されなかったため,プログラムは,加算で
t[1]
という初期化されていない値を使用しています。
配列
t
を含むメモリ・ブロックは,それを割り当てた呼び出しスタックによって識別されます。
-g
オプションを指定してコードがコンパイルされている場合,スタック変数は名前で識別されます。
---------------------------------------------------- ruh -- 1 -- ex.c: 12: reading uninitialized heap at byte 8 of 160-byte block GetArray ex, ex.c, line 12 main ex, ex.c, line 20 __start ex This block at address 0x14000ca20 was allocated at: malloc ex GetArray ex, ex.c, line 10 main ex, ex.c, line 20 __start ex
次のログ・エントリは,プログラムが,配列の終わりの位置を 1 つだけ過ぎたメモリ位置に書き込んで,重要なデータ,または Third Degree 内部のデータ構造体を重ね書きした可能性があることを示しています。 後で報告されるエラーの中には,このエラーの結果である可能性があります。
---------------------------------------------------- wih -- 2 -- ex.c: 14: writing invalid heap 1 byte beyond 160-byte block GetArray ex, ex.c, line 14 main ex, ex.c, line 20 __start ex This block at address 0x14000ca20 was allocated at: malloc ex GetArray ex, ex.c, line 10 main ex, ex.c, line 20 __start ex
次のログ・エントリは,以前に解放されたメモリを解放しているときにエラーが発生したことを示しています。
free
関数の呼び出しに伴うエラーでは,Third Degree は,通常,3 つの呼び出しスタックを与えます。
エラーが発生した呼び出しスタック
オブジェクトが割り当てられた呼び出しスタック
オブジェクトが解放された呼び出しスタック
プログラムをチェックしてみると,GetArray
への 2 回目の呼び出し (20 行目) によってオブジェクトが解放されたこと (14 行目) と,同じオブジェクトをもう一度解放しようとしていること (21 行目) がわかります。
---------------------------------------------------- fof -- 3 -- ex.c: 22: freeing already freed heap at byte 0 of 32-byte block free ex main ex, ex.c, line 22 __start ex This block at address 0x14000d1a0 was allocated at: malloc ex GetArray ex, ex.c, line 10 main ex, ex.c, line 21 __start ex This block was freed at: free ex GetArray ex, ex.c, line 15 main ex, ex.c, line 21 __start ex
詳細については,7.3 節を参照してください。
7.2.3.2 メモリ・リーク
次のプログラムの抜粋は,プログラム終了時のリーク検出を選択した場合 (省略時の設定) に生成されたレポートを示しています。 このレポートは,重要度と呼び出しスタックでソートされたメモリ・リークのリストを示しています。
--------------------------------------------------------------- --------------------------------------------------------------- New blocks in heap after program exit Leaks - blocks not yet deallocated but apparently not in use: * A leak is not referenced by static memory, active stack frames, or unleaked blocks, though it may be referenced by other leaks. * A leak "not referenced by other leaks" may be the root of a leaked tree. * A block referenced only by registers, unseen thread stacks, mapped memory, or uninstrumented library data is falsely reported as a leak. Instrumenting shared libraries, if any, may reduce the number of such cases. * Any new leak lost its last reference since the previous heap report, if any. A total of 160 bytes in 1 leak were found: 160 bytes in 1 leak (including 1 not referenced by other leaks) created at: malloc ex GetArray ex, ex.c, line 10 main ex, ex.c, line 20 __start ex Objects - blocks not yet deallocated and apparently still in use: * An object is referenced by static memory, active stack, or other objects. * A leaked block may be falsely reported as an object if a pointer to it remains when a new stack frame or heap block reuses the pointer's memory. Using the option to report uninitialized stack and heap may avoid such cases. * Any new object was allocated since the previous heap report, if any. A total of 0 bytes in 0 objects were found:
ソースをチェックすると,GetArray
の最初の呼び出しによってメモリ・オブジェクトが解放されなかったことと,それがプログラムの他の箇所でも解放されていないことがわかります。
さらに,このオブジェクトへのポインタがプログラムのどこにもないため,"not referenced by other leaks
" と認定されます。
この区別は,大きなメモリ・リークの本当の原因を発見するのに役立つことがよくあります。
たとえば,大きなツリー構造で,ルートへのポインタが消去されたと仮定します。 構造内のすべてのブロックがリークしていますが,ルートを指すポインタが失われていることがリークの本当の原因です。 ルート以外のすべてのブロックは,その構造へのポインタを持っているため,他のリークからだけですが,ルートだけが特別に識別されます。 したがって,これがメモリ損失の原因である可能性が高いと考えられます。
詳細については,7.4 節を参照してください。
7.2.3.3 ヒープ・ヒストリ
ヒープ・ヒストリが使用可能な場合,Third Degree は動的に割り当てられたメモリに関する情報を収集します。 この情報は,アプリケーションが解放するすべてのブロック,およびプログラムの実行が終了した時点でまだ存在しているすべてのブロック (メモリ・リークを含む) について収集されます。 次のプログラムの抜粋は,ヒープ割り当てヒストリ・レポートを示しています。
---------------------------------------------------------------- ---------------------------------------------------------------- Heap Allocation History for parent process Legend for object contents: There is one character for each 32-bit word of contents. There are 64 characters, representing 256 bytes of memory per line. '.' : word never written in any object. 'z' : zero in every object. 'i' : a non-zero non-pointer value in at least one object. 'pp': a valid pointer or zero in every object. 'ss': a valid pointer or zero in some but not all objects. 192 bytes in 2 objects were allocated during program execution: ------------------------------------------------------------------ 160 bytes allocated (8% written) in 1 objects created at: malloc ex GetArray ex, ex.c, line 10 main ex, ex.c, line 20 __start ex Contents: 0: i.ii.................................... ------------------------------------------------------------------ 32 bytes allocated (38% written) in 1 objects created at: malloc ex GetArray ex, ex.c, line 10 main ex, ex.c, line 21 __start ex Contents: 0: i.ii....
このサンプル・プログラムでは,合計 192 バイト (8*(20+4)) の 2 個のオブジェクトが割り当てられています。 各オブジェクトは,異なる呼び出しスタックから割り当てられているため,ヒストリには 2 つのエントリがあります。 各配列の最初の数バイトだけが有効な値に設定され,その結果,ここに示されているような書き込み率になります。
このサンプル・プログラムが実際のアプリケーションだとすると,初期化されている動的メモリが極端に少ないことから,アプリケーションによるメモリの使用が非効率的であることがわかります。
詳細については,7.4.4 項を参照してください。
7.2.3.4 メモリ・レイアウト
レポートのメモリ・レイアウト・セクションでは,プログラムが使用するメモリの概要を,サイズおよびアドレス範囲により示します。 次のプログラムの抜粋は,メモリ・レイアウト・セクションを示しています。
----------------------------------------------------------------- ----------------------------------------------------------------- memory layout at program exit heap 40960 bytes [0x14000c000-0x140016000] stack 2720 bytes [0x11ffff560-0x120000000] ex data 48528 bytes [0x140000000-0x14000bd90] ex text 1179648 bytes [0x120000000-0x120110000]
示されたヒープ・サイズおよびアドレス範囲は,プログラムの終了時に
sbrk(0)
により返された値 (ヒープ・ブレーク) を反映します。
このため,サイズは,プロセスに割り当てられたヒープ・スペース全体を表します。
Third Degree は,この
sbrk(0)
の解釈を変更するような
malloc
変数の使用をサポートしません。
スタック・サイズとアドレス範囲は,プログラムの実行中にメイン・スレッドのスタック・ポインタが達する最下位アドレスを反映します。
つまり,Third Degree は,計測機構付きプロシージャが呼び出されるたびに,最下位アドレスを追跡します。
この値がスタック・サイズの最大値を反映するには,すべてのシェアード・ライブラリが計測機構付きである必要があります
(たとえば,スレッド化されていないプログラムでは,
third
(1)-all
オプションを使用し,dlopen(3)
を使ってロードしたライブラリでは
-incobj
オプションを使用します)。
スレッドのスタック (pthread_create
を使用して作成された) は含まれません。
データやテキストのサイズおよびアドレス範囲は,実行可能プログラムの静的な部分や各シェアード・ライブラリがロードされた場所を示します。
7.3 Third Degree エラー・メッセージの解釈
Third Degree は,回復不可能なエラーとメモリ・アクセス・エラーの両方を報告します。 回復不可能なエラーには,次のものが含まれます。
不正パラメータ
たとえば,malloc(-10)
など。
失敗した割り当て機能
たとえば,malloc
が 0 を返して,利用可能なメモリがないことを示した場合など。
非ゼロの引数を指定した
brk
関数への呼び出し
Third Degree では,非ゼロの引数を指定して
brk
を呼び出すことはできません。
シグナル・ハンドラにおけるメモリ割り当ての不許可
回復不可能なエラーが起こると,計測機構付きアプリケーションが,ログ・ファイルをフラッシュした後にクラッシュします。
アプリケーションがクラッシュした場合には,まずログ・ファイルをチェックしたのち,
third
(1)-g
を指定して,デバッガのもとでそれを再実行します。
メモリ・エラーには,次のものが含まれます (英字 3 文字の短縮形で表します)。
名前 | エラー |
ror |
範囲外の読み込み。 ヒープ,スタック,静的領域のいずれでもない (たとえば NULL)。 |
ris |
スタック内の無効なデータの読み取り。 多くの場合,配列境界エラー。 |
rus |
スタック内の,有効だか初期化されていない記憶位置の読み取り。 |
rih |
ヒープ内の無効なデータの読み取り。 多くの場合,配列境界エラー。 |
ruh |
ヒープ内の,有効だが初期化されていない記憶位置の読み取り。 |
wor |
範囲外の書き込み。 ヒープ,スタック,静的領域のいずれでもない。 |
wis |
スタックへの無効なデータの書き込み。 多くの場合,配列境界エラー。 |
wih |
ヒープへの無効なデータを書き込み。 多くの場合,配列境界エラー。 |
for |
範囲外の解放。 ヒープ,スタックのいずれでもない。 |
fis |
スタック内のアドレスの解放。 |
fih |
ヒープ内の無効なアドレスの解放。 有効なオブジェクトがない。 |
fof |
すでに解放されたオブジェクトの解放。 |
fon |
null ポインタの解放 (単なる警告)。 |
mrn |
malloc
による null の戻し。 |
特定のメモリ・エラーの報告は,-ignore
オプションを 1 つまたは複数指定することによって抑制できます。
これは,ソースのないライブラリ関数内でエラーが発生した場合に役立つことがあります。
Third Degree を使用すると,個々のプロシージャおよびファイル内の特定のメモリ・エラーを特定の行番号で抑制できます。
詳細は,
third
(1)
代わりに,-excobj
を指定するか,または
-all
や
-incobj
オプションを省略することによって,チェックのためにライブラリを選択しないという方法もあります。
7.3.1 エラーの修正とアプリケーションの再試行
Third Degree が,計測機構付きプログラムから多数の書き込みエラーを報告する場合は,最初のいくつかのエラーを修正してから,プログラムを再計測します。
書き込みエラーは悪化する可能性があるだけではなく,Third Degree 内部のデータ構造体を破壊することもあります。
7.3.2 初期化されていない値の検出
初期化されていない値の使用を検出するという Third Degree の手法により,動作していたプログラムが,計測時に異常終了することがあります。
たとえば,プログラムが,malloc
関数への最初の呼び出しでゼロに初期化されたブロックが返されるということを前提にしている場合は,Third Degree がすべてのブロックを非ゼロ値 (省略時の設定では 0xfff8a5a5) にしてしまうため,そのプログラムの計測機構付きバージョンは異常終了します。
逆参照またはその他の方法でこの初期化されていない値を使用したために発生したシグナルを検出した場合には,Third Degree は次の形式のメッセージを表示します。
*** Fatal signal SIGSEGV detected. *** This can be caused by the use of uninitialized data. *** Please check all errors reported in app.3log.
初期化されていないデータの使用は,計測機構付きプログラムがクラッシュする最大の原因です。 問題の原因を判別するには,まず,初期化されていないスタックの読み取りと初期化されていないヒープの読み取りによるエラーがないかどうかを,ログ・ファイルでチェックします。 ほとんどの場合,ログ・ファイルの最後のエラーのうちの 1 つが問題の原因です。
エラーの発生源を示している問題がある場合は,それが本当に初期化されていないデータの読み取りに起因しているかどうかを,-uninit
オプション (またはオプション全体) から
heap
および
stack
オプションを削除することで確認できます。
stack
を削除すると,通常,Third Degree が各プロシージャのエントリで実行する,新規に割り当てられたスタック・メモリの非ゼロ値による埋め込みが不能に設定されます。
同様に,heap
の削除は,各動的メモリ割り当てで実行される,ヒープ・メモリの初期化を不能に設定します。
これらのオプションの一方または両方を使用することにより,計測機構付きプログラムの動作を変更して,そのプログラムを正常に完了させることができる場合があります。
これは,計測機構付きプログラムがどのタイプのエラーでクラッシュしたかを判別するのに役立ちます。
その結果,ログ・ファイル内の特定のメッセージに集中できるようになります。
代わりに,計測機構付きプログラムをデバッガで実行して
(
third
(1)-g
オプションを使用),失敗の原因を削除する方法もあります。
メモリ・リークをチェックしたいだけの場合は,-uninit
オプションを使用する必要はありませんが,-uninit
オプションを使用すると,より正確なリークのレポートを得ることができます。
プログラムによってシグナル・ハンドラが設定される場合は,Third Degree が省略時のシグナル・ハンドラを変更しても,それを妨げる可能性はほとんどありません。
Third Degree は,通常プログラムのクラッシュを起こすシグナル (SIGILL
,
SIGTRAP
,
SIGABRT
,
SIGEMT
,
SIGFPE
,
SIGBUS
,
SIGSEGV
,
SIGSYS
,
SIGXCPU
,および
SIGXFSZ
を含む) に対してだけ,シグナル・ハンドラを定義します。
Third Degree によるシグナルの処理は,-signals
オプションを指定することにより不能にすることができます。
7.3.3 ソース・ファイルの探索
Third Degree は,各エラー・メッセージの前に,コンパイラが使用するスタイルでファイルおよび行番号を付加します。 たとえば,次のようになります。
----------------------------------------------------- fof -- 3 -- ex.c: 21: freeing already freed heap at byte 0 of 32-byte block free malloc.c main ex.c, line 21 __start crt0.s
Third Degree は,エラーの発生源にできる限り近づいて指摘しようとします。 通常は,この例のように,エラー発生時の呼び出しスタックの最上位に近いプロシージャのファイルと行番号を表示します。 ただし,それがライブラリの中にあったり,現在のディレクトリになかったりすると,Third Degree はこのソース・ファイルを見つけることができません。 この場合,Third Degree は,指摘可能なソース・ファイルを見つけるまで,呼び出しスタックを下へ移動します。 通常は,これはライブラリ・ルーチン呼び出しのポイントです。
これらのエラー・メッセージにタグをつけるには,Third Degree がプログラムのソース・ファイルの位置を判断しなければなりません。
ソース・ファイルを含むディレクトリで Third Degree を実行している場合,Third Degree はそのディレクトリにあるソース・ファイルを探索します。
そうでない場合,Third Degree の探索パスにディレクトリを追加するには,-use
オプションを 1 つまたは複数指定します。
これにより,Third Degree は,他のディレクトリに含まれるソース・ファイルを見つけることができるようになります。
各ソース・ファイルの位置は,そのファイルが探索された探索パスの最初のディレクトリです。
7.4 アプリケーションによるヒープ使用の検査
適切に割り当てられたメモリだけがアクセスおよび解放されていることを確認する実行時の検査に加え,Third Degreeは,アプリケーションによるヒープの使用法を理解するために,次の 2 つの方法を提供しています。
メモリ・リークを見つけて,報告できる。
ヒープの内容をリストできる。
省略時の設定では,Third Degree はプログラムの終了時にリークがないかどうかを検査します。
この節では,Third Degree により供給された情報を使用して,アプリケーションによるヒープの使用法を分析する方法を説明します。
7.4.1 メモリ・リークの検出
メモリ・リークは,使用中のポインタが存在しないヒープ内のオブジェクトです。 このオブジェクトは,アクセスすることができず,使用も解放もできません。 これは役に立たず,消えることもなく,メモリの無駄使いです。
Third Degree は,単純なトレース・アンド・スィープ (trace-and-sweep) のアルゴリズムを使用して,メモリ・リークを見つけます。 Third Degree はルートのセット (現在アクティブなスタックおよび静的領域) から開始して,ヒープ内のオブジェクトへのポインタを見つけ,これらのオブジェクトに訪問済みのマークをつけます。 次に,これらのオブジェクトの中にある潜在的なすべてのポインタを再帰的に見つけ,最後にヒープをスィープして,マークが付いていないオブジェクトをすべて報告します。 マークの付いていないこれらのオブジェクトがリークです。
トレース・アンド・スィープのアルゴリズムによって,循環構造も含め,すべてのリークが見つかります。 このアルゴリズムは保守的であり,型情報がない場合,適切に境界合わせされ,ヒープ内の有効なオブジェクトの内部を指し示す 64 ビット・パターンは,すべてポインタとみなされます。 このように想定することにより,次のような問題が滅多に起こらないようにします。
Third Degree は,オブジェクトの先頭または内部のいずれかへのポインタを実ポインタとみなします。 これらが含むアドレスへのポインタをもたないオブジェクトだけがリークとみなされます。
他のプロセスのアドレス空間に格納したり,またはコード化することにより,計測機構付きアプリケーションが本当のポインタを隠している場合は,Third Degree は見かけ上のリークを報告します。
Third Degree でそのようなアプリケーションを計測するときは,-mask
オプションを指定します。
このオプションを使用すると,すべての潜在的なポインタに対して AND 演算子として適用されるマスクが指定できます。
たとえば,ポインタの先頭の 3 ビットをフラグとして使用する場合は,0x1fffffffffffffff のマスクを指定します。
詳細については,
third
(1)
Third Degree は,ヒープ・ポインタと似ているビット・パターン (文字列,整数,浮動小数点数,およびパック構造体など) があると,それを本当のポインタと混同し,そのために本当のリークを見落とす可能性があります。
Third Degree は,最適化されたコードがメモリではなくレジスタにだけ格納したポインタは認識しません。 その結果,誤ったリーク・レポートが作成されることがあります。
リーク・レポートの精度を最大限にするには,-uninit h+s
および
-all
オプションを使用します。
ただし,-uninit
オプションを指定すると,プログラムが異常終了する恐れがあり,-all
オプションでは,計測と実行時間が増加します。
このため,Leaks と Objects のリストだけをチェックして,プログラム・エラーの可能性を調べてください。
7.4.2 ヒープの読み取りとリーク・レポート
コマンド・オプションを指定すると,すべてのヒープ・オブジェクトまたはリークについての前回のレポートまたはリスト以降の,新しいヒープ・オブジェクトまたはリークだけをリストした,ヒープおよびリークの増分レポートを Third Degree に生成させることができます。
これらのレポートは,プログラムの終了時,あるいはユーザ指定の関数への
n
回目の呼び出しの前または後に要求できます。
-blocks
,-every
,-before
,および
-after
オプションの詳細については,
third
(1)-blocks
オプション (省略時の設定) では,ヒープ内のリークとオブジェクトの両方がレポートされるため,間違ったタイプとして分類されたイベント内のリークやオブジェクトを見落とすことがありません。
.3log
ファイルには,間違った分類が生じる可能性のある状況が,レポートの正確さを向上させる方法と一緒に記述されています。
Third Degree は,レポートされたブロックが本当にリークしていることを示す証拠を見つけているが,一方,その証拠は,オブジェクトとしてレポートされたブロックがそうでないことを示しているので,リークのレポートは注意深く見る必要があります。 ただし,プログラムのデバッグやチェックにより,そうでないことがわかった場合は,ツールが証拠を誤って解釈したと推断することができます。
Third Degree は,関係するバイト数に基づいて重要度を減少させることにより,メモリ・オブジェクトおよびリークをレポートにリストします。 そこでは,同じ呼び出しスタックで割り当てられたオブジェクトは,まとめてグループ化されます。 たとえば,同一の呼び出しシーケンスによって,1 バイトのオブジェクトが 100 万割り当てられた場合には,Third Degree はそれらを 100 万の割り当てを含む 1 MB のグループとして報告します。
オブジェクトまたはリークが同じであり,レポートの中でグループ化する必要がある場合 (またはオブジェクトやリークが異なり,そのためにグループ化するべきでない場合) に Third Degree に指示するには,-depth
オプションを指定します。
このオプションは,Third Degree がリークまたはオブジェクトを区別するために使用する呼び出しスタックの深さを設定します。
たとえば,オブジェクトに対して 1 という深さを指定した場合,Third Degree は,呼び出し元の関数に関係なく,ヒープ内の有効なオブジェクトを割り当てた関数と行番号により,それらをグループ化します。
逆に,リークに対して非常に大きな深さを指定した場合,Third Degree は,main
から上方の,同一の呼び出しスタックのあるポイントに割り当てられたリークだけをグループ化します。
ほとんどのヒープのレポートでは,最初の 2,3 のエントリが記憶域のほとんどの原因となっていますが,小さなエントリの非常に長いリストがあることもあります。
レポートの長さを制限するには,-min
オプションが使用できます。
このオプションは,リークしたメモリ総量,またはオブジェクトが使用中のメモリ総量のパーセンテージをしきい値として定義します。
残りの小さいリークまたはオブジェクトの合計が,このしきい値よりも小さい場合には,Third Degree は,これらを最後の 1 つのエントリにまとめてグループ化します。
注意
realloc
関数は (malloc
,copy
,およびfree
への呼び出しを含めることにより),常に新規のオブジェクトを割り当てるため,これを使用すると,Third Degree レポートの解釈が直観に反したものになります。 オブジェクトは,異なる識別で 2 回リストされることがあります。リークとオブジェクトは相互に排他的です。 オブジェクトは,ルートから到達可能でなければなりません。
メモリ・リークを探索する時点は,常にはっきりしているわけではありません。 省略時の設定では,Third Degree はプログラムの終了後にリークがないかどうかをチェックしますが,これが常にユーザの要求するものとは限りません。
リークの検出は,使用されている構造体がすべて有効範囲内にあるうちに,プログラムの終了にできるだけ近いところで行うのが最もよい方法です。
ただし,リーク検出用のルートは,スタックおよび静的領域の内容であることを憶えておいてください。
プログラムが
main
から戻って終了し,その構造体の 1 つへの唯一のポインタがスタックに保持されている場合には,リーク探索の間,このポインタはルートとして参照されず,リークしたメモリとして誤って報告されることになります。
たとえば,次のような場合です。
1 main (int argc, char* argv[]) { 2 char* bytes = (char*) malloc(100); 3 exit(0); 4 }
このプログラムを計測する場合に,-blocks all -before exit
を指定すると,Third Degree はリークを検出しません。
プログラムが
exit
関数を呼び出すとき,main
の変数はすべてまだ有効範囲内にあります。
ここで,次の例を検討してください。
1 main (int argc, char* argv[]) { 2 char* bytes = (char*) malloc(100); 3 }
同じオプションを指定して (または指定しないで) このプログラムを計測すると,チェックが行われる前に
main
が戻ったために,Third Degree のリーク検査によって記憶域リークが報告されることがあります。
これら 2 つの動作内容は,bytes
が本当のリークか,単に
main
が戻った時点でまだ使用中のデータ構造体であるかにより,いずれも正しいものです。
リーク検出を実行する時点を理解するために,プログラムを慎重に読むのではなく,指定したプロシージャへの指定した回数の呼び出しの後に,新しいリークがないかを検査できます。
次のオプションを指定して,省略時のリーク・チェックを無効にし,プロシージャ
proc_name
への各 10,000 回目の呼び出しの前にリークを要求します。
-blocks cancel -blocks new -every 10000 -before proc_name
-history
オプションを使用して,このプログラムを計測すると,Third Degree がプログラムのヒープ・ヒストリを生成できます。
ヒープ・ヒストリを使用することにより,プログラムが実行中に動的メモリをどのように使用したかがわかります。
たとえば,この機能を使用すると,データ構造体の未使用のフィールドを削除したり,または処理中のフィールドをパックしてメモリを効率的に使用することができます。
ヒープ・ヒストリは,割り当てられたけれど,アプリケーションが使用しなかったメモリ・ブロックも示します。
ヒープ・ヒストリが使用可能に設定されている場合,Third Degree は,動的に割り当てられた各オブジェクトについての情報を,それがアプリケーションによって解放される時点で収集します。 プログラムの実行が完了すると,Third Degree は,まだ有効なすべてのオブジェクトについてこの情報 (メモリ・リークも含む) をアセンブルします。 各オブジェクトごとに,Third Degree はオブジェクトの内容を見て,各ワードを,アプリケーションが書き込まなかったもの,0,有効なポインタ,またはその他の値に分類します。
Third Degree は次に,各オブジェクトに関する情報を,プログラム内の同じ呼び出しスタックで割り当てられたその他のオブジェクトすべてについて収集した情報とマージします。 その結果,任意の型のすべてのオブジェクトの使用に関する累積的な様子が提供されます。
Third Degree では,プログラムの存在期間中に割り当てられたすべてのオブジェクトと,それらの内容が使用された目的の要約が提供されます。
このレポートは,割り当てポイント (たとえば
malloc
または
new
などの割り当て機能を持つ関数が呼び出された箇所の呼び出しスタック) ごとに 1 つのエントリを示します。
エントリは,割り当て量で降順にソートされます。
各エントリは,次の内容を提供します。
割り当てられているすべてのオブジェクトに関する情報
割り当てられている総バイト数
割り当てられている総オブジェクト数
割り当てられたオブジェクトのうち,書き込みが行われたバイトのパーセンテージ
呼び出しスタック,およびその呼び出しスタックが割り当てたすべてのオブジェクトの内容の累積マップ
各エントリの内容部分は,オブジェクトがどのように使用されたかを記述します。
割り当てられたすべてのオブジェクトが同じサイズではない場合,Third Degree は,すべてのオブジェクトに共通な最小のサイズだけを考慮します。
非常に大きな割り当てに関しては,オブジェクトの最初の部分の内容だけを要約します。
省略時の値では,これは最初の 1 KB です。
-size
オプションを指定することによって,最大サイズの値が調整できます。
エントリの内容部分では,Third Degree は次の文字の 1 つを使用して,チェックする 32 ビットの各ロングワードを表します。
文字 | 説明 |
ドット(.) | オブジェクトに書き込まれなかったロングワードを示し,メモリが浪費されている明らかなしるしです。 通常,より詳しい分析を行って,これが単にテストが不十分でこのフィールドを使用しなかっただけのか,フィールドのスワップまたはよりよい型を選択すれば解決する埋め込みの問題であるのか,あるいはこのフィールドがもはや使われていないものなのかを確認する必要があります。 |
z | すべてのオブジェクトで,値が常に 0 (ゼロ) であるフィールドを示します。 |
pp | ポインタ,つまりスタック,静的データ領域,ヒープへの有効なポインタだった (または 0 だった) 64 ビットの量を示します。 |
ss | サムタイム・ポインタを示します。 このロングワードは,最低 1 つのオブジェクトではポインタと似ていましたが,すべてのオブジェクトでそうであったわけではありません。 これは,一部のインスタンスの初期化されていないポインタまたは共用体である可能性があります。 ただし,これは重大なプログラミング・エラーのしるしかもしれません。 |
i | 最低 1 つのオブジェクトでなんらかの非ゼロ値で書き込まれたが,どのオブジェクトでもポインタ値を含んでいなかったロングワードを示します。 |
エントリが 100 MB を割り当てているとリストされていても,割り当てられたオブジェクトが任意の時点で 100 MB のヒープ・ストレージを使用したことを意味するわけではありません。 これは累積の数字であり,この時点までのプログラムの存在期間全体で 100 MB が割り当てられていることを示しています。 この 100 MB は,解放されたかもしれないし,リークしたか,あるいはまだヒープ内にあるかもしれません。 この数字は,単にこの割り当て関数が非常に多くの処理をしていることを示しています。
理想的には,実際に書き込まれたバイトの小数部は,常に 100 パーセントに近くならなければなりません。 ずっと低い場合には,割り当てられたバイトの一部が使用されていません。 パーセンテージが低い一般的な理由には,次のものがあります。
大きなバッファが割り当てられたが,これまで小さな部分しか使用されていません。
任意の型のすべてのオブジェクトの各部分が使用されていません。 これらは,忘れられたフィールドか,または C 構造体の境界合わせ規則に起因する実在のフィールド間の埋め込みの場合があります。
あるオブジェクトが割り当てられたが,使用されていません。 オブジェクトのポインタが破棄された場合,リーク検出によりこれらのオブジェクトが発見されることがあります。 しかし,それらが空きリストに保持されている場合は,ヒープ・ヒストリでしか見つけられません。
7.5 シンボル情報が不十分なプログラムにおける Third Degree の使用
計測した実行可能プログラムにシンボル情報がほとんどなく,Third Degree がいくつかのプログラム記憶位置を正確に指摘することが困難な場合,Third Degree は,プロシージャ名,ファイル名,または行番号が認識できないというメッセージを出力します。 たとえば,次のようになります。
------------------------------------------------------ rus -- 0 -- reading uninitialized stack at byte 40 of 176 in frame of main proc_at_0x1200286f0 libc.so pc = 0x12004a268 libc.so main app, app.c, line 16 __start app
Third Degree はスタック・トレースのプロシージャ名をプリントしようとしますが,(これが静的なプロシージャであるために) プロシージャ名が失われている場合は,Third Degree は計測機構付きプログラムのプログラム・カウンタをプリントします。 この情報により,デバッガを使って記憶位置を見つけることができます。 プログラム・カウンタが使用できない場合には,Third Degree は名前のないプロシージャのアドレスをプリントします。
もっと頻繁に起こるのは,ファイルが省略時の
-g0
オプションでコンパイルされたためにファイル名または行番号が使用できない場合です。
この場合,Third Degree は,プロシージャが見つかったオブジェクトの名前をプリントします。
このオブジェクトは,メイン・アプリケーションまたはシェアード・ライブラリのいずれかです。
省略時の設定では,エラー・レポートがプリントされるのは,ソース・ファイル名と行番号のあるスタック・フレームが,スタックの上の 2 つのフレーム内に表示される場合に限ります。
これにより,システム・ライブラリ内の高度に最適化されたアセンブラ言語コードによって生成される可能性のある偽のレポートが隠されます。
デバッグ不能なプロシージャに関連するレポートが隠されるのを少なく (多く) するには,-hide
オプションを使用します。
シンボル情報がないためにデバッグが困難な場合は,シンボル情報を多くしてプログラムを再コンパイルすることを検討します。
-g
または
-g1
オプションをつけて再コンパイルし,-x
オプションなしでリンクします。
-g
オプションを使用すると,レポートには,前述の例にあるようなバイト・オフセットではなく,変数名が表示されます。
7.6 Third Degree エラー・レポートの有効性検査
まれに,次のような見かけ上のエラーが発生することがあります。
次に示す例のように,変数,配列の要素,または 32 ビットより小さい構造体のメンバ (たとえば
short
,char
,ビット・フィールドなど) に対して行われた変更。
void Packed() { char c[4]; struct { int a:6; int b:9; int c:4} x; c[0] = c[1] = 1; /* rus errors here ... */ x.a = x.c = x.e = 3; /* ... maybe here */ }
strcpy
,memcpy
,printf
などについてレポートされたありそうもないエラー・メッセージは無視してください。
Third Degree は,新規に割り当てられたメモリに特別な値を埋め込んで,初期化されていない変数への参照を検出します (7.3.2 項を参照)。 この特別な値をメモリに明示的に格納し,それを後で読み取るプログラムは,見かけ上の「初期化されていないメモリの読み取り」エラーを起こすことがあります。
可変サイズのスタック・フレームはサポートされていません。 "invalid stack" に関するメッセージはすべて無視してください。
誤った正の数を見つけたと思う場合は,エラーが報告されたプロシージャにデバッガを使用することにより確認できます。
Third Degree によって報告されるすべてのエラーは,アプリケーションのロードおよび格納時に検出され,エラー・レポートに示される行番号は,逆アセンブルによる出力に示されるものと一致します。
-g
オプションを指定してプログラムのコンパイルおよび計測を行ってから,デバッグをします。
7.7 検出されないエラー
Third Degree は,次のような,実在のエラーの検出に失敗することがあります。
32 ビットよりも小さい量の演算のエラー (たとえば,char
,short
,ビット・フィールドなど) は,検出されない可能性があります。
-uninit repeat
オプションは,より多くのロード/ストア操作をチェックすることにより,そのようなエラーを見つけることができます。
これらは,Third Degree では,通常,リスクが非常に小さいためチェックの必要がないとみなされているものです。
Third Degree は,ヒープにおける誤ったオブジェクトの偶発的なアクセスは検出できません。
検出できるのは,オブジェクトからのメモリ・アクセスだけです。
たとえば,Third Degree は,a[last+100]
が
b[0]
と同じアドレスであることを判断することはできません。
オブジェクトに付加される埋め込みの量を変更することにより,これが発生する可能性を減少させることができます。
これを行うには,-pad
オプションを指定します。
Third Degree は,アプリケーションが配列のスタック・フレームの終わりまたはそのヒープ・オブジェクトを超えた場合に,これを検出できないことがあります。
Third Degree は,ヒープ内のオブジェクトを「ガード・ワード」で囲むため,小さな配列境界エラーを見落とすことがあります (ガードはオーバシュートを検出します)。
スタックでは,隣接メモリにローカル変数が含まれている可能性が高く,Third Degree は,より大きな境界エラーの検出に失敗することがあります。
たとえば,sprintf
演算をはるかに小さなローカル・バッファに対して実行することは検出されますが,配列の境界を 2,3 のワード分超えただけで,十分なローカル変数が配列を取り囲んでいる場合には,エラーは検出されない可能性があります。
配列の境界違反をもっと厳密に検出するには,cc
コマンドの
-check_bounds
オプションを使用します。
ポインタをコード化したり,あるいはそれらをヒープ・オブジェクトの内部だけにとどめておくことによってポインタを隠すと,Third Degree のリーク検出の有効性が低下します。
コンパイラの最適化が無効に設定されている (つまり,-O0 および -inline none オプションが指定されている) 場合,Third Degree はより多くの初期化されていない変数を検出することがあります。
時々,古いポインタがメモリ内で見つかったために,リークが報告されないことがあります。 初期化されていないヒープ・メモリのチェックを選択すると (-uninit heap),この問題を減らすことができます。
コンパイラが本質的でないと見なす命令は最適化されることがあるため,どの程度の最適化であってもリーク報告の結果がゆがめられます。