dbx コマンドによるデバッグ ホーム目次前ページへ次ページへ索引


第 9 章

実行時検査

実行時検査 (RTC) を使用すると、開発段階でアプリケーションの実行時エラーを自動的に検出できます。RTC では、メモリーアクセスエラーおよびメモリーリークエラーなどの実行時エラーを検出して、メモリーの使用状況を監視できます。

この章は次の各節から構成されています。

概要

RTC は、統合的なデバッグ機能であり、標本コレクタによるパフォーマンスデータの収集時を除けば、実行時にあらゆるデバッグ機能を利用できます。

次に、RTC の機能を簡単に説明します。

-g フラグを付けてコンパイルすると、RTC エラーメッセージでのソース行番号の関連性が与えられます。RTC は、最適化 -O フラグによってコンパイルされたプログラムを検査することもできます。-g オプションによってコンパイルされていないプログラムについては、特殊な考慮事項があります。

RTC を実行するには、dbx コマンドを入力するか、「デバッグ」ウィンドウや「実行時検査」ウィンドウを利用します。Sun WorkShop オンラインヘルプの「デバッグウィンドウの使い方」の「実行時検査の開始」を参照してください。

RTC を使用する場合

大量のエラーが一度に検出されないようにするには、RTC を開発サイクルの初期の段階で使用します。この段階では、プログラムの構成要素となる個々のモジュールを開発します。この各モジュールを実行する単位テストを作成し、RTC を各モジュールごとに 1 回ずつ使用して検査を行います。これにより、一度に処理するエラーの数が減ります。すべてのモジュールを統合して完全なプログラムにした場合、新しいエラーはほとんど検出されません。エラー数をゼロにした後でモジュールに変更を加えた場合にのみ、RTC を再度実行してください。

RTC の必要条件

RTC を使用するには、次の要件を満たす必要があります。

制限事項

RTC は、8Mバイトより大きなプログラムのテキスト領域およびデータ領域を処理しません。詳細については「RTC の 8M バイト制限」を参照してください。

実行可能イメージに特殊ファイルを挿入すると、8Mバイトより大きなプログラムのテキスト領域とデータ領域を処理することができます。

RTC の使用

実行時検査を使用するには、使用したい検査の種類を指定します。

メモリー使用状況とメモリーリーク検査を有効化

メモリーの使用状況とメモリーリークの検査を有効にするには、次のように入力します。

(dbx) check -memuse

メモリーの使用状況とメモリーリークの検査は、「デバッグ」ウィンドウでも有効にできます。Sun WorkShop オンラインヘルプの「デバッグウィンドウの使い方」の「すべてのメモリーリークの表示」を参照してください。

MUC か MLC がオンになっている場合、showblock コマンドを実行する、所定のアドレスにおけるヒープブロックに関する詳細情報を表示できます。この詳細情報では、ブロックの割り当て場所とサイズを知ることができます。詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「showblock コマンド」を参照してください。

メモリーアクセス検査を有効化

メモリーアクセス検査だけをオンにするには、次のように入力します。

(dbx) check -access

メモリーアクセスの検査も「デバッグ」ウィンドウで有効にできます。詳細については、Sun WorkShop オンラインヘルプの「「デバッグウィンドウの使い方」の「メモリーアクセス検査を有効にする」を参照してください。

すべての RTC を有効化

メモリーリーク、メモリー使用状況、およびメモリーアクセスの各検査をオンにするには、次のように入力します。

(dbx) check -all

詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「check コマンド」を参照してください。

RTC を無効化

RTC をすべて無効にするには、次のように入力します。

(dbx) uncheck -all

詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「uncheck コマンド」を参照してください。

プログラムを実行

目的のタイプの RTC を有効にしてテストするプログラムを実行します。この場合、ブレークポイントを設定してもしなくてもかまいません。

プログラムは普通に実行されますが、すべてのメモリーアクセスがその妥当性を確認するために検査されるので、実行速度は遅くなります。無効なアクセスがあると dbx によって検出され、そのタイプとエラーの発生場所が表示されます。制御はユーザーに戻ります (dbx 環境変数 rct_auto_continueon になっている場合を除きます (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「rtc_auto_continue 環境変数」参照))。

次に、dbx コマンドを実行します。where コマンドでは現在のスタックトレースを呼び出すことができます。また print を実行すれば変数を確認できます。エラーが致命的でなければ、cont コマンドでプログラムの処理を続行します。プログラムは次のエラーまたはブレークポイントまで、どちらか先に検出されるところまで実行されます。詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「cont コマンド」を参照してください。

rtc_auto_continueon に設定されている場合、RTC はそのままエラーを求めて自動的に続行されます。検出したエラーは、dbx 環境変数 rtc_error_log_name で指定したファイルにリダイレクトされます (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「rtc_error_log _file_name 環境変数」を参照してください)。

RTC エラーの報告が不要な場合は、suppress コマンドを使用します。詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「suppress コマンド」を参照してください。

次の例は、hello.c と呼ばれるプログラムのメモリーアクセス検査とメモリー使用状況検査をオンにする方法を示しています。

% cat -n hello.c
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4
     5 char *hello1, *hello2;
     6
     7 void
     8 memory_use()
     9 {
    10      hello1 = (char *)malloc(32);
    11      strcpy(hello1, "hello world");
    12      hello2 = (char *)malloc(strlen(hello1)+1);
    13      strcpy(hello2, hello1);
    14 }
    15
    16 void
    17 memory_leak()
    18 {
    19      char *local;
    20      local = (char *)malloc(32);
    21      strcpy(local, "hello world");
    22 }
    23

  

(続き)

 
    24 void
    25 access_error()
    26 {
    27      int i,j;
    28
    29      i = j;
    30 }
    31
    32 int
    33 main()
    34 {
    35      memory_use();
    36      access_error();
    37      memory_leak();
    38      printf("%s\n", hello2);
    39      return 0;
    40 }

 
% cc -g -o hello hello.c
% dbx -C hello
hello のシンボル情報を読んでいます
rtld /usr/lib/ld.so.1 のシンボル情報を読んでいます
librtc.so のシンボル情報を読んでいます
libc.so.1 のシンボル情報を読んでいます
libdl.so.1 のシンボル情報を読んでいます
(dbx) check -access
アクセス検査 - ON
(dbx) check -memuse
メモリー使用状況検査 - ON
(dbx) run
実行中: hello 
(プロセス id 18306)
実行時検査を有効にしています...終了
非初期化領域からの読み取り (rui):
4 バイト読み取り を アドレス 0xeffff068 で しようとしました
    それは 96 バイト 現スタックポインタより上 です
変数は 'j' です。
現関数 :access_error
   29           i = j;
(dbx) cont

  

(続き)

 
メモリーリーク検査中...

 
実際のリークの報告       (実際のリーク:         1  合計サイズ:      32 バイト)

 
合計    ブロック リーク    割り当て呼出しスタック
サイズ    数     ブロック
                 アドレス
======  ====== ==========  =======================================
    32       1    0x21aa8  memory_leak < main 
 

 
起こり得るリークの報告  (起こり得るリーク:       0  合計サイズ       0 バイト)
メモリー使用状況検査中...

 
ブロック使用量の報告     (ブロック使用量:       2  合計サイズ:      44 バイト)
 

 
  合計  割合 ブロック 平均   割り当て呼出しスタック
 サイズ  %     数   サイズ
======= ==== ====== ======  =======================================
     32  72%      1     32  memory_use < main 
     12  27%      1     12  memory_use < main 
 
実行完了。終了コードは、0 です

  

関数 access_error() は、初期化される前の変数 j を読み取ります。RTC は、このアクセスエラーを非初期化領域からの読み取り (rui) として報告します。

関数 memory_leak() は、終了する前に local を解放 (free()) しません。
memory_leak() が終了してしまうと、local がスコープ外になり、行 20 で確保したブロックがリークになります。

プログラムは、常にスコープ内にある大域変数 hello1hello2 を使用します。これらの変数はいずれも、使用中ブロック (biu) として報告される割り当て済みメモリーを動的に指します。

メモリーアクセスエラーの検出 (SPARC のみ)

RTC では、読み取り、書き込み、メモリー解放の各操作を監視することによって、プログラムがメモリーに正しくアクセスするかどうかを検査します。

プログラムは、さまざまな方法で間違ってメモリーを読み取ったり、メモリーに書き込んだりすることがあります。このようなエラーをメモリーアクセスエラーといいます。たとえば、ヒープブロックの free() 呼び出しを使用して、または関数がローカル変数にポインタを返したために、プログラムが参照するメモリーブロックの割り当てが解放されている可能性があります。アクセスエラーはプログラムでワイルドポインタの原因になり、間違った出力やセグメント不正など、プログラムの異常な動作を引き起こす可能性があります。メモリーアクセスエラーには、検出が非常に困難なものもあります。

RTC は、プログラムによって使用されているメモリーの各ブロックの情報を追跡するテーブルを管理します。プログラムがメモリー操作を行うと、RTC は関係するメモリーブロックの状態に対してその操作が有効かどうかを判断します。メモリーの状態として次のものがあります。

アクセスエラーを見つけるには、アクセス検査をオンにし、プログラムにアクセスエラーのリストを作成させるのが一番簡単な方法です。 RTC を使用してメモリーアクセスエラーを見つける方法は、コンパイラがプログラム中の構文エラーを見つける方法と似ています。いずれの場合でも、プログラム中のエラーが発生した位置と、その原因についてのメッセージとともにエラーのリストが生成され、リストの先頭から順に修正していかなければなりません。これは、あるエラーがほかのエラーと関連して連結されたような作用があるためです。連結の最初のエラーが先頭の原因となり、そのエラーを修正することにより、そのエラーから派生した他の問題も解決されることがあります。たとえば、初期化されていないメモリーの読み取りにより、不正なポインタが作成されるとします。すると、これが原因となって不正な読み取りと書き込みのエラーが発生し、それがまた原因となってさらに別の問題が発生するというようなことになる場合があります。

メモリーアクセスエラーの報告

メモリーアクセスエラーを検出すると RTC は次の情報を出力します。

エラー 情報
種類 エラーの種類。
アクセス 試みられたアクセスの種類 (読み込みまたは書き込み)。
サイズ 試みられたアクセスのサイズ。
アドレス 試みられたアクセスのアドレス
詳細 アドレスについてのさらに詳しい情報。たとえば、アドレスがスタックの近くに存在する場合、現在のスタックポインタからの相対位置が与えられます。アドレスが複数存在する場合、一番近いブロックのアドレス、サイズ、相対位置が与えられます。
スタック エラー時の呼び出しスタック (バッチモード)。
割り当て addr がヒープにある場合、最も近いヒープブロックの割り当てトレースが与えられます。
場所 エラーが発生した位置。行が特定できる場合には、ファイル名、行番号、関数が示されます。行番号が分からないときは関数とアドレスが示されます。


代表的なアクセスエラーは次のとおりです。

非初期化領域からの読み取り (rui):
4 バイト読み取り を アドレス 0xefffee50 で しようとしました
    それは 96 バイト 現スタックポインタより上 です
変数は 'j' です。
現関数 :rui
  12           i = j;

メモリーアクセスエラー

RTC は、以下のメモリーアクセスエラーを検出します。

メモリーリークの検査

メモリーリークとは、プログラムで使用するために割り当てられているが、プログラムのデータ領域中のいずれも指していないポインタをもつ、動的に割り当てられたメモリーブロックを言います。そのようなブロックは、メモリーのどこに存在しているかプログラムにわからないため、プログラムに割り当てられていても使用することも解放することもできません。RTC はこのようなブロックを検知し、報告します。

メモリーリークは仮想メモリーの使用を増やし、一般的にメモリーの断片化を招きます。その結果、プログラムやシステム全体のパフォーマンスが低下する可能性があります。

メモリーリークは、通常、割り当てメモリーを解放しないで、割り当てブロックへのポインタを失うと発生します。メモリーリークの例を以下に示します。

void
foo()
{
    char *s;
    s = (char *) malloc(32);
 
    strcpy(s, "hello world");
 
    return; /* s が解放されていない。foo が戻るとき、malloc されたブロック
               を指しているポインタが存在しないため、ブロックはリークする*/
}

リークは、API の不正な使用が原因で起こる可能性があります。

void
printcwd()
{

 
    printf("cwd = %s\n", getcwd(NULL, MAXPATHLEN));

 
    return; /* libc の関数 getcwd() は、最初の引数が NULL の場合 malloc
            された領域へのポインタを返す。プログラムは、これを解放する必要
            がある。この場合、ブロックが解放されていないため、結果的にリー
            クになる。*/
}

メモリーリークを防ぐには、必要のないメモリーは必ず解放します。また、メモリーを確保するライブラリ関数を使用する場合は、メモリーを解放することを忘れないでください。

解放されていないブロックを「メモリーリーク」と呼ぶこともあります。ただし、この定義はあまり使用されません。プログラムが短時間で終了する場合でも、通常のプログラミングではメモリーを解放しないからです。プログラムにそのブロックに対するポインタがある場合、RTC はそのようなブロックはメモリーリークとして報告しません。

メモリーリーク検査の使用

RTC では、以下のメモリーリークエラーを検出します。

リークの可能性

RTC が「リークの可能性」として報告するエラーには 2 種類あります。1 つは、ブロックの先頭を指すポインタが検知されず、ブロックの内部を指しているポインタが見つかった場合です。これは、ブロック中のアドレス (aib) エラーとして報告されます。このようなブロック内部を指すポインタが見つかった場合は、プログラムに実際にメモリーリークが発生しています。ただし、プログラムによってはポインタに対して故意にそのような動作をさせている場合があり、これは当然メモリーリークではありません。RTC はこの違いを判別できないため、本当にリークが発生しているかどうかはユーザー自身の判断で行う必要があります。

もう 1 つのリークの種類は、レジスタ中のアドレス (air) エラーとして報告されるリークです。これは、ある領域を指すポインタがデータ空間中には存在せず、レジスタ内に存在する場合です。レジスタがブロックを不正に指していたり、古いメモリーポインタが残っている場合には、実際にメモリーリークが発生しています。ただし、コンパイラが最適化のために、ポインタをメモリーに書き込むことなく、レジスタのブロックに対して参照させることがありますが、この場合はメモリーリークではありません。プログラムが最適化され、showleaks コマンドでエラーが報告された場合のみ、リークでない可能性があります。詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「showleaks コマンド」を参照してください。


注 - RTC リーク検査では、標準 libc malloc/free/realloc 関数またはアロケータをこれらの関数に基いて使用する必要があります。ほかのアロケータについては、「RTC での修正継続機能の使用」を参照してください。

リークの検査

メモリーリーク検査がオンの場合、メモリーリークの走査は、テスト中のプログラムが終了する直前に自動的に実行されます。検出されたリークはすべて報告されます。プログラムを、kill コマンドによって強制的に終了してはなりません。次に、典型的なメモリーリークエラーによるメッセージを示します。

メモリーリーク (mel):
大きさ 1024 バイト のリークのあるブロックをアドレス
0x21718 に発見
割り当て時のスタックの状態
[1]
foo() 行番号 63 "test.c"
[2] main() 行番号 47
"test.c"

「デバッグ」ウィンドウで、コールスタック場所のハイパーテキストリンクをクリックすると、エディタウィンドウのソースコード行に移動できます。

プログラムには通常 main (FORTRAN 77 では MAIN) 手続きが存在します。プログラムは exit(3) が呼び出されるか、main から返った時点で終了します。いずれの場合でも、main のすべての局所変数はプログラムが停止するまでスコープから出ず、それらを指す特定のヒープブロックはすべてメモリーリークとして報告されます。

main() に割り当てられているヒープブロックはプログラムでは解放しないのが一般的です。これらのヒープブロックはプログラムが停止するまでスコープ内に残り、プログラムの停止後オペレーティングシステムによって自動的に解放されるためです。main() に割り当てられたブロックがメモリーリークとして報告されないようにするには、main() が終了する直前にブレークポイントを設定しておきます。プログラムがそこで停止したとき、RTC の showleaks コマンドを実行すれば、main() とそこで呼び出されるすべての手続きで参照されなくなったヒープブロックのすべてが表示されます。

詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「showleaks コマンド」を参照してください。

または、「デバッグ」ウィンドウでもメモリーリークを検査できます。Sun WorkShop オンラインヘルプの「デバッグウィンドウの使い方」の「すべてのメモリーリークの表示」を参照してください。

メモリーリークの報告を理解する

リーク検査を有効にすると、プログラムの終了時にリークレポートが自動的に生成されます。kill コマンドでプログラムを終了した場合を除き、リークの可能性がすべて報告されます。レポートの詳細レベルは、dbx 環境変数 rtc_mel_at_exit (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「rtc_mel_at_exit 環境変数」参照) か、「デバッグオプション」ダイアログの「自動リーク報告」オプション (Sun WorkShop オンラインヘルプの「デバッグウィンドウの使い方」の「自動リーク報告の生成」参照) で制御します。デフォルトで、非冗長リークレポートが生成されます。

レポートは、リークのサイズによってソートされます。実際のメモリーリークが最初に報告され、次に可能性のあるリークが報告されます。詳細レポートには、スタックトレース情報の詳細が示されます。行番号とソースファイルが使用可能であれば、これらも必ず含まれます。

次のメモリーリークエラー情報が、2 種類の報告のどちらにも含まれます。

リークしたブロックが割り当てられた場所
リークしたブロックのアドレス
リークしたブロックのサイズ
割り当て時の呼び出しスタック。check -frames によって制約される


「実行時検査」ウィンドウに表示される非冗長レポートでは、エラー情報がテーブルにカプセル化されますが、冗長レポートでは、エラーごとに独立したエラーメッセージが表示されます。どちらもソースコードにおけるエラー位置までのハイパーテキストリンクを備えています。

次に、対応する簡易メモリーリークレポートを示します。

実際のリークの報告       (実際のリーク:         3  合計サイズ:   2427 バイト)

 
合計        ブロック  リーク              割り当て呼出しスタック
サイズ                     ブロック
                                    アドレス
======    ======      ========   =====================================
  1852       2      -      true_leak < true_leak 
   575       1    0x22150  true_leak < main 

 
起こり得るリークの報告  (起こり得るリーク:      1  合計サイズ      8 バイト)

 
合計   ブロック リーク     割り当て呼出しスタック
サイズ  数    ブロック
          アドレス
======  ======  ==========  =====================================
     8       1    0x219b0  in_block < main 

次に、典型的な詳細リークレポートを示します。

実際のリークの報告       (実際のリーク:        3  合計サイズ:   2427 バイト)

 
メモリーリーク (mel):
大きさ 1 バイト のリークのあるブロックをアドレス 0x20f18 に発見
割り当て時のスタックの状態:
	[1] true_leak() 行番号 220 "leaks.c"
	[2] true_leak() 行番号 224 "leaks.c"

 

 
起こり得るリークの報告  (起こり得るリーク:      1  合計サイズ      8 バイト)

 
メモリーリークの可能性 -- ブロック中のアドレス (aib):
大きさ 4 バイト のリークのあるブロックをアドレス 0x20ef8 に発見
割り当て時のスタックの状態:
	[1] in_block() 行番号 177 "leaks.c"
	[2] main() 行番号 100 "leaks.c"

リークレポートの生成

showleaks コマンドを使用すると、いつでもリークレポートを要求することができます。このコマンドは、前回の showleaks コマンド以降の新しいメモリーリークを報告するものです。詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「showleaks コマンド」を参照してください。

リークレポート

リークレポートの数が多くなるのを避けるため、RTC は同じ場所で割り当てられたリークを自動的に 1 つにまとめて報告します。1 つにまとめるか、それぞれ各リークごとに報告するかは、一致フレーム数引数によって決まります。この引数は、check -leaks コマンドを実行する際は -match m オプション、showleaks コマンドを実行する際は -m オプションで指定します。呼び出しスタックが 2 つ以上のリークを割り当てる際に m 個のフレームと一致した場合は、リークは 1 つにまとめて報告されます。

以下の 3 つの呼び出しシーケンスを考えてみます。

ブロック 1 ブロック 2 ブロック 3
[1] malloc [1] malloc [1] malloc
[2] d() at 0x20000 [2] d() at 0x20000 [2] d() at 0x20000
[3] c() at 0x30000 [3] c() at 0x30000 [3] c() at 0x31000
[4] b() at 0x40000 [4] b() at 0x41000 [4] b() at 0x40000
[5] a() at 0x50000 [5] a() at 0x50000 [5] a() at 0x50000


これらのブロックがすべてメモリーリークを起こす場合、m の値によって、これらのリークを別々に報告するか、1 つのリークが繰り返されたものとして報告するかが決まります。m が 2 のとき、ブロック 1 とブロック 2 のリークは 1 つのリークが繰り返されたものとして報告されます。これは、malloc() の上にある 2 つのフレームが共通しているためです。ブロック 3 のリークは、c() のトレースがほかのブロックと一致しないので別々に報告されます。m が 2 より大きい場合、RTC はすべてのリークを別々に報告します (malloc はリークレポートでは表示されません)。

一般に、m の値が小さければリークのレポートもまとめられ、m の値が大きければまとめられたリークレポートが減り、別々のリークレポートが生成されます。

メモリーリークの修正

RTC からメモリーリーク報告を受けた場合にメモリーリークを修正する方法についてのガイドラインを以下に示します。

詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「showleaks コマンド」を参照してください。

メモリー使用状況検査の使用

メモリ使用状況検査は、使用中のヒープメモリーすべてを確認することができます。この情報によって、プログラムのどこでメモリーが割り当てられたか、またはどのプログラムセクションが大半の動的メモリーを使用しているかを知ることができます。この情報は、プログラムの動的メモリー消費を削減するためにも有効であり、パフォーマンスの向上に役立ちます。

メモリー使用状況検査は、パフォーマンス向上または仮想メモリーの使用制御に役立ちます。プログラムが終了したら、メモリー使用状況レポートを生成できます。メモリー使用情報は、メモリーの使用状況を表示させるコマンドを使用して、プログラムの実行中に随時入手することもできます。詳細については、Sun WorkShop オンラインヘルプのdbx コマンドの使い方」の「shownenyse コマンド」を参照してください。

メモリー使用状況検査をオンにすると、リーク検査もオンになります。プログラム終了時のリークレポートに加えて、使用中ブロック (biu) レポートも得ることができます。デフォルトでは、使用中ブロックの簡易レポートがプログラムの終了時に生成されます。これは、dbxenv 変数 rtc_biu_at_exit によって指定できます。(Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「rtc_biu_at_exit 環境変数」参照) か、「デバッグオプション」ダイアログの「自動リーク報告」オプション (Sun WorkShop オンラインヘルプの「デバッグウィンドウの使い方」の「自動リーク報告の生成」参照) で制御します。

次に、典型的な簡易メモリー使用状況レポートを示します。

ブロック使用量の報告   (ブロック使用量: 5   合計サイズ:   40 バイト)

 
 合計    割合 ブロック  平均     割り当て呼び出しスタック
 サイズ    %    数   サイズ
======= ==== ====== ======  =====================================
     16  40%     2      8  nonleak < nonleak 
      8  20%     1      8  nonleak < main 
      8  20%     1      8  cyclic_leaks < main 
      8  20%     1      8  cyclic_leaks < main 

次に、対応する詳細メモリー使用状況レポートを示します。

ブロック使用量の報告   (ブロック使用量: 5   合計サイズ:   40 バイト)

 
ブロック使用状況 (biu):
サイズ 8 バイト のブロックをアドレス 0x25498 で見つけました (合計 40.00%)
割り当て時のスタックの状態:
     [1] nonleaks() 行番号 182 "memuse.c"
     [2] nonleaks() 行番号 185 "memuse.c"

 
ブロック使用状況(biu):
サイズ 8 バイト のブロックをアドレス 0x21898 で見つけました (合計 20.00%)
割り当て時のスタックの状態:
     [1] nonleaks() 行番号 182 "memuse.c"
     [2] main() 行番号 74 "main.c"

 
ブロック使用状況 (biu):
サイズ 8 バイト のブロックをアドレス 0x21958 で見つけました (合計 20.00%)
割り当て時のスタックの状態:
     [1] cycle_leaks() 行番号 154 "memuse.c"
     [2] main() 行番号 118 "main.c"

 
ブロック使用状況(biu):
サイズ 8 バイト のブロックをアドレス 0x21978 で見つけました (合計 20.00%)
割り当て時のスタックの状態:
     [1] cycle_leaks() 行番号 115 "memuse.c"
     [2] main() 行番号 118 "main.c"

showmemuse コマンドを使用すると、メモリー使用状況レポートをいつでも要求できます。

エラーの抑止

RTC はエラーレポートの数や種類を限定するよう、エラーの抑制機能を備えています。エラーが発生してもそれが抑制されている場合は、エラーは無視され、報告されずにプログラムは継続します。

エラーは suppress コマンド (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「suppress コマンド」参照) で抑止できます。最新のエラー報告を抑止するには、「実行時検査」ウィンドウの「最後に報告されたリークの抑止」ボタン (Sun WorkShop オンラインヘルプの「デバッグウィンドウの使い方」の「最後に報告されたエラーの抑止」参照) を使用します。

エラー抑止を取り消すには、unsuppress コマンド (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「unsuppress コマンド」参照) を使用します。

抑止機能は同じデバッグ節内の run コマンドの実行期間中は有効ですが、debug コマンドを実行すると無効になります。

抑止のタイプ

次の抑制機能があります。

スコープと種類による抑制

どのエラーを抑止するかを指定する必要があります。以下のように、プログラムのどの部分に抑制を適用するかを指定できます。

大域 スコープが指定されていないと全体のスコープが対象になり、
すべてのプログラムに適用されます。
ロードオブジェクト 共有ライブラリなど、すべてのロードオブジェクトが対象になります。
ファイル 特定のファイルのすべての関数が対象になります。
関数 特定の関数が対象になります。
特定のソース行が対象になります。
アドレス 特定のアドレスが対象になります。


最新エラーの抑止

デフォルトで RTC を実行すると、最新のエラーで同じエラーが繰り返し報告されることがなくなります。この機能は、dbx 環境変数 rtc_auto_suppress で制御します。rtc_auto_suppresson のとき (デフォルト)、特定個所の特定エラーは最初の発生時にだけ報告され、その後同じエラーが同じ場所で発生しても報告が繰り返されることはありません。最新エラーを抑止すると、繰り返し実行するループに 1 つのエラーがあっても、それが何度も報告されることがなく、便利です。

エラー報告回数の制限

dbx 環境変数 rtc_error_limt では、報告されるエラーの回数を制御します。エラー制限は、アクセスエラーとリークエラーに別々に設定します。たとえば、エラー制限を 5 に設定すると、プログラムの終了時のリークレポートと、showleaks コマンドの実行ごとに、アクセスエラーとリークエラーがそれぞれ最高で 5 回報告されます。デフォルトは 1000 です。

エラー抑止の例

次の例では、main.cc はファイル名、foobar は関数を示し、a.out は実行可能ファイルの名前を示します。

割り当てが関数 foo で起こったメモリーリークは報告しません。

suppress mel in foo

libc.so.1 から割り当てられた使用中のブロック報告を抑止します。

suppress biu in libc.so.1

a.out の非初期化機能からの読み取りを抑止します。

suppress rui in a.out

ファイル main.cc の非割り当てメモリーからの読み取りを報告しません。

suppress rua in main.cc

main.cc の行番号 10 での重複解放を抑止します。

suppress duf at main.cc:10

関数 bar のすべてのエラー報告を抑止します。

suppress all in bar

詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「suppress コマンド」を参照してください。

デフォルトの抑止

RTC では、-g オプション (記号) を指定してコンパイルを行わなくてもすべてのエラーを検出できます。しかし、非初期化メモリーからの読み取りなど、正確さを保証するのに 記号 (-g) 情報が必要な特定のエラーもあります。このため、a.outrui や 共有ライブラリの rui, aib, air など特定のエラーは、記号情報が取得できない場合は、デフォルトで抑制されます。この動作は、suppressunsuppress コマンドの -d オプションを使用することで変更できます。

たとえば、以下を実行すると、RTC は記号情報が存在しない (-g オプションを指定しないでコンパイルした) コードについて「非初期化メモリーからの読み取り (rui)」を抑制しません。

unsuppress -d rui

詳細については、Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「unsuppress コマンド」を参照してください。

抑止によるエラーの制御

プログラムが大きい場合、エラーの数もそれに従って多くなることが予想されます。このような場合は、suppress コマンドを使用することにより、エラーレポートの数を管理しやすい大きさまで抑制し、一度で修正するエラーを制限します。抑制するエラーの数を徐々に減らしながら、この動作を繰り返してください。

たとえば、一度で検出するエラーをタイプによって制限できます。一般的によくあるエラーのタイプは rui、rua、wua に関連したもので、この順序で検出されます。rui エラーはそれほど致命的なエラーではなく、このエラーが検出されてもたいていの場合プログラムは問題なく実行終了します。それに比べて ruawua エラーは不正なメモリーアドレスにアクセスし、ある種のコーディングエラーを引き起こすため、問題は深刻です。

まず ruirua エラーを抑制し、wua エラーをすべて修正した後、もう一度プログラムを実行します。次に rui エラーだけを抑制し、rua エラーをすべて修正した後、もう一度プログラムを実行します。さらにエラーの抑制をせずに、すべての rui エラーを修正します。最後にプログラムを実行し、エラーがすべて修正されたことを確認してください。

最新のエラー報告を抑止するには、「suppress -last」を実行します (または「実行時検査」ウィンドウの「最後に報告されたエラーの抑止」ボタンをクリックします)。

子プロセスにおける RTC の実行

子プロセスで RTC を実行するには、dbx 環境変数 rtc_inheriton に設定します。デフォルトでは off になります (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「rtc_inherit 環境変数」参照)。

親で RTC が有効になっていて、dbx 環境変数 follow_fork_modechild に設定されているときに dbx を実行すると子プロセスの RTC を実行できます (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「follow_fork_mode 環境変数」参照)。

分岐が発生すると、dbx は子に RTC を自動的に実行します。プログラムが exec () を呼び出すと、exec () を呼び出すプログラムの RTC 設定がそのプログラムに渡ります。

特定の時間に RTC の制御下におくことができるプロセスは 1 つだけです。次に例を示します。

% cat -n program1.c
     1 #include <sys/types.h>
     2 #include <unistd.h>
     3 #include <stdio.h>
     4
     5 int
     6 main()
     7 {
     8      pid_t child_pid;
     9      int parent_i, parent_j;
    10
    11      parent_i = parent_j;
    12
    13      child_pid = fork();
    14
    15      if (child_pid == -1) {
    16          printf("parent: Fork failed\n");
    17          return 1;
    18      } else if (child_pid == 0) {
    19          int child_i, child_j;
    20
    21          printf("child: In child\n");
    22          child_i = child_j;
    23          if (execl("./program2", NULL) == -1) {
    24              printf("child: exec of program2 failed\n");
    25              exit(1);
    26          }
    27      } else {
    28          printf("parent: child's pid = %d\n", child_pid);
    29      }
    30      return 0;
    31 }
%

   

 % cat -n program2.c
     1
     2 #include <stdio.h>
     3
     4 main()
     5 {
     6      int program2_i, program2_j;
     7
     8      printf ("program2: pid = %d\n", getpid());
     9      program2_i = program2_j;
    10
    11      malloc(8);
    12
    13      return 0;
    14 }
% 

   

  
















RTC は親プロセス、program1 の最初のエラーを報告します。
% cc -g -o program1 program1.c
% cc -g -o program2 program2.c
% dbx -C program1
program1 のシンボル情報を読んでいます
rtld /usr/lib/ld.so.1 のシンボル情報を読んでます
librtc.so のシンボル情報を読んでいます
libc.so.1 のシンボル情報を読んでいます
libdl.so.1 のシンボル情報を読んでいます
(dbx) check -all
アクセス検査 - ON
メモリー使用状況検査 - ON
(dbx) dbxenv follow_fork_mode child
(dbx) run
実行中: program1 
(プロセス id 3885)
実行時検査を有効にしています...終了
非初期化領域からの読み取り (rui):
4 バイト読み取り を アドレス 0xeffff110 で しようとしました
    それは 104 バイト 現スタックポインタより上 です
変数は 'parent_j' です。
現関数 :main
   11   	parent_i = parent_j;


  

  


follow_fork_modechild に設定されているため、フォークが起こると、エラー検査が親プロセスから子プロセスに切り替えられます。



RTC は子プロセスのエラーを報告します。





program2 の実行が起こると、RTC 設定値は program2 から継承されるため、アクセスおよびメモリー使用状況の検査がそのプロセスに対して有効になります。






(dbx) cont
dbx: 警告: フォークしました。親プロセス内での実行時検査機能は休
止します
プロセス 3885 から切り離し中
parent: child's pid = 3885
プロセス 10711 に接続しました。
_libc_fork で停止しました アドレス 0xef6b6040
0xef6b6040: _fork+0x0008:	bgeu    _fork+0x30
現関数 :main
   13				child_pid = fork();
(dbx) cont
child: In child
非初期化領域からの読み取り (rui):
4 バイト読み取り を アドレス 0xeffff108 で しようとしました
    それは 96 バイト 現スタックポインタより上 です
変数は 'child_j' です。
現関数 :main
   22						child_i = child_j;
(dbx) cont
dbx: プロセス 10711 は exec("./program2") をするところです
dbx: プログラム "./program2" が今 exec されました
dbx: オリジナルプログラムに戻るには "debug $oprog" を使用しま
す
program2 のシンボル情報を読んでいます
すでに読んでいるので、ld.so.1 を飛ばします
すでに読んでいるので、librtc.so を飛ばします
すでに読んでいるので、libc.so.1 を飛ばします
すでに読んでいるので、libdl.so.1 を飛ばします
実行時検査を有効にしています...終了
main で停止しました 行番号 8  ファイル "program2.c"
    8				printf("program2: pid = %d\n", getpid());
(dbx) cont
program2: pid = 13886


  

   

RTC は、実行されたプログラム、program2 のアクセスエラーを報告します。




RTC は、RTC 制御下にある間に終了したプロセス、program2 に関するメモリー使用状況レポートとメモリーリークレポートを出力します。
非初期化領域からの読み取り (rui):
4 バイト読み取り を アドレス 0xeffff13c で しようとしました
    それは 100 バイト 現スタックポインタより上 です
変数は 'program2_j' です。
現関数 :main
    9				program2_i = program2_j;
(dbx) cont 
メモリーリーク検査中...
実際のリークの報告  (実際のリーク:   1  合計サイズ:    8 バイト)

合計    ブロック リーク 割り当て呼出しスタック
サイズ   数    ブロック
           アドレス
======  ====== ==========  ===========================
     8       1    0x20c50  main 

 
起こり得るリークの報告 (起こり得るリーク: 0 合計サイズ: 0 バイ
ト)

 
実行完了。終了コードは、0 です


  

接続されたプロセスへの RTC の使用

RTC は接続されたプロセスに機能します。ただし、接続されたプロセスに RTC を使用するには、librtc.so を事前に読み込んでおく必要があります。たとえば、librtc.so は、Sun WorkShop の lib ディレクトリにインストールされます。したがって、製品を /opt にインストールすると、librtc.so/opt/SUNWspro/lib にインストールされます。

librtc.so を事前に読み込むには、次のように入力します。

% setenv LD_PRELOAD path-to-librtc/librtc.so

librtc.so を常時読み込んだ状態にせず、必要なときにだけ読み込まれるように LD_PRELOAD を設定してください。次に例を示します。

% setenv LD_PRELOAD...
% start-your-application
% unsetenv LD_PRELOAD

プロセスに接続したら、RTC を有効にすることができます。

接続したいプログラムがフォークされるか、または別のプログラムによって実行された場合は、LD_PRELOAD をフォークを行うメインプログラムに設定する必要があります。LD_PRELOAD の設定値は fork/exec を通して継承されます。

RTC での修正継続機能の使用

RTC を修正継続機能とともに使用すると、プログラミングエラーを簡単に分離して修正することができます。修正継続機能を組み合わせて使用すると、デバッグに要する時間を大幅に削減することができます。次に例を示します。

% cat -n bug.c
     1  #include <stdio.h>
     2  char *s = NULL;
     3   
     4  void
     5  problem()
     6  {
     7          *s = 'c';
     8  }
     9   
    10  main()
    11  {
    12          problem();
    13          return 0;
    14  }
    15   
% cat -n bug-fixed.c
     1  #include stdio.h
     2  cahr *s = NULL;
     3   
     4  void
     5  problem()
     6  {
     7   
     8          s = (cahr *)malloc(1);
     9          *s = 'c';
    10  }
    11   
    12  main()

    13  {
    14          problem();
    15          return 0;
    16  }

 
% cc -g bug.c
% dbx -C a.out
a.out のシンボル情報を読んでいます
rtld /usr/lib/ld.so.1 のシンボル情報を読んでます
librtc.so のシンボル情報を読んでいます
libc.so.1 のシンボル情報を読んでいます
libdl.so.1 のシンボル情報を読んでいます
(dbx) check -access
アクセス検査 - ON
(dbx) run
実行中: a.out 
(プロセス id 15052)
実行時検査を有効にしています...終了
非割り当て領域への書き込み (wua):
1 バイト書き込み を NULL ポインタを通して しようとしました。
現関数 :problem
    7   	*s = 'c';
(dbx) pop
main で停止しました 行番号 12  ファイル "bug.c"
   12   	problem();
(dbx) cp bug-fixed.c bug.c
(dbx) fix
修正中 "bug.c" ......
 pc は "bug.c":14  に移動しました
main で停止しました 行番号 14  ファイル "bug.c"
   14   	problem();
(dbx) cont

 
実行完了。終了コードは、0 です
(dbx) quit
'a.out' の下記のモジュールは変更されました (修正済み):
bug.c
プログラムを再構築することをお忘れなく。

修正と継続についての詳細は、ëÊ 11 èÕを参照してください。

実行時検査アプリケーションプログラミング
インタフェース

リーク検出およびアクセスの両方の検査では、共有ライブラリ libc.so 内の標準ヒープ管理ルーチンを使用する必要があります。これは、RTC がプログラム内のすべての割り当てと開放を追跡できるためです。アプリケーションの多くは、独自のメモリー管理ルーチンを malloc/free にかぶせて作成したり、または最初から作成します。独自のアロケータ (専用アロケータと呼ばれる) を使用すると、RTC はそれらを自動的に追跡できません。したがって、それらの不正な使用によるリークエラーとメモリーアクセスエラーを知ることができません。

ただし、RTC には専用アロケータを使用するための API があります。この API を使用すると、専用アロケータを、標準ヒープアロケータと同様に扱うことができます。API 自体はヘッダーファイル rtc_api.h に入っており、WorkShop の一部として出されます。マニュアルページの rtc_api(3x) には、RTC API 入口の詳細が記載されています。

専用アロケータがプログラムヒープを使用しない場合の RTC アクセスエラーレポートには小さな違いがいくつかあります。エラーレポートに、割り当て項目は含まれません。

バッチモードでの RTC の使用

bcheck(1) は、dbx の RTC 機能の便利なバッチインタフェースです。これは、dbx のもとでプログラムを実行し、デフォルトにより RTC エラー出力をデフォルトファイルの program.errs に入れます。

bcheck は、メモリーリーク検査、メモリーアクセス検査、メモリー使用状況検査のいずれか、またはこのすべてを実行できます。デフォルトでは、リーク検査だけが実行されます。この使用方法の詳細については、bcheck(1) のマニュアルページを参照してください。

bcheck 構文

bcheck の構文は次のとおりです。

bcheck [-access | -all | -leaks | -memuse] [-o logfile] [-q] 
[-s
script] program [args]

-o logfile オプションを使用すると、ログファイルに別の名前を指定することができます。-s script オプションはプログラムの実行前に script を実行します。ファイル script に含まれる dbx コマンドを読み取ることができます。script ファイルには通常、suppressdbxenv などのコマンドが含まれていて、bcheck によるエラー出力を調整します。

-g オプションは、bcheck を完全な静止状態にして、プログラムと同じ状況になります。これは、スクリプトまたはメークファイルで bcheck を使用したい場合に便利です。

bcheck 構文

hello に対してリーク検査だけを実行します。

bcheck hello

mach に引数 5 を付けてアクセス検査だけを実行します。

bcheck -access mach 5

cc に対してメモリー使用状況検査だけを静止状態で実行し、通常の終了状況で終了します。

bcheck -memuse -q cc -c prog.c

プログラムは、実行時エラーがバッチモードで検出されても停止しません。すべてのエラー出力がエラーログファイル logfile にリダイレクトされます。しかしプログラムは、ブレークポイントを検出するか、またはプログラムが割り込みを受けると停止します。

バッチモードでは、完全なスタックバックトレースが生成されて、エラーログファイルにリダイレクトされます。スタックフレームの数は、dbxenv 変数 stack_max_size によって指定できます。

ファイル logfile がすでに存在する場合、bcheck はそのファイルの内容を消去してから、そこに出力をリダイレクトします。

dbx からバッチモードを直接有効化

バッチモードに似たモードは、dbx 環境変数 rtc_auto_continuertc_error_log_file_name から直接有効にできます (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「rtc_auto_continue 環境変数」と「rtc_error_log_file_name 環境変数」参照)。

rtc_auto_continueon に設定されていると、RTC はそのままエラーを求めて自動的に実行されます。検出したエラーは、dbx 環境変数 rtc_error_log_name で指定したファイルにリダイレクトされます (Sun WorkShop オンラインヘルプの「dbx コマンドの使い方」の「rtc_error_log_file_name 環境変数」参照)。デフォルトログファイル名は、/tmp/dbx.errorlog.uniqueid です。すべてのエラーを端末にリダイレクトするには、rtc_error_log_file_name 環境変数を /dev/tty に設定します。

rtc_auto_continue はデフォルトで off です。

トラブルシューティングのヒント

プログラム中でエラー検査がオンになっていて、プログラムが実行中の場合、次のエラーが検出されることがあります。

librtc.so と dbx とのバージョンが合いません。; エラー検査を休止状態にしま
した

これは、RTC を接続されたプロセスに使用していて、LD_PRELOAD を、各自の Sun WorkShop dbx に添付されたもの以外の librtc.so バージョンに設定した場合に起こる可能性があります。これを修正するには、LD_PRELOAD の設定値を変更してください。

パッチエリアが遠すぎます (8MB の制限); アクセス検査を休止状態にしました

RTC は、アクセス検査を有効にするためにロードオブジェクトに十分に近いパッチスペースを検出できませんでした。この章に後述される「rtc_patch_area」の項を参照してください。

RTC の 8M バイト制限

アクセス検査を実行するために、dbx の RTC 機能は各ロードおよびストア命令を、パッチ領域への分岐命令と置き換えます。この分岐命令の有効範囲は 8Mバイトです。これは、デバッグされたプログラムが、置き換えられた特定のロード/ストア命令の 8Mバイトのアドレス空間をすべて使いきってしまった場合、パッチ領域を保存する場所がなくなることを意味します。

RTC がメモリーへのすべてのロードおよびストアにまったく割り込めない場合、RTC は正確な情報を提供できないので完全に無効になります。リークの検査は影響を受けません。

この制約にぶつかった場合、dbx は何らかの処置を施します。その結果、問題が修正できれば続行しますが、問題が修正できない場合は、エラーメッセージを表示しアクセス検査を終了します。

8M バイトの制限値に達したら、以下の対策をとってください。

  1. 64 ビット SPARC V9 の代わりに 32 ビット SPARC V8 を使用します。

    -xarch=v9 オプションでコンパイルされたアプリケーションで 8M バイト問題が発生するときは、32 ビットバージョンのアプリケーションでメモリーテストをしてください。64 ビットアドレスには長いパッチ命令シーケンスが必要であり、32 ビットアドレスを使用すれば 8M バイトの制限を緩和できるからです。これでも問題が解決しない場合は、32 ビットプログラムと 64 ビットプログラムいずれの場合にも、以下の対策をとってください。

  2. トラップを使用します。

    UltraSparc ハードウェアでは、ブランチではなくトラップハンドラを呼び出す機能が dbx に追加されました。トラップハンドラへの制御の移行には非常に時間がかかりますが (最大で 10 分)、8M バイトの制限がなくなります。トラップハンドラを有効にするには、dbx rtc_use_traps 環境変数を使用します (「dbxenv コマンドでの dbx 環境変数の設定」参照)。ハードウェアが UltraSparc であれば、この変数は 32 ビットプログラムと 64 ビットプログラムで使用できます。ハードウェアを検査するには、システムコマンド uname -m を使用し、結果が sun4u であるかを確認します。

  3. パッチ領域オブジェクトファイルを追加します。

    rtc_patch_area シェルスクリプトを使用し、大きな実行可能ファイルや共有ライブラリの中間にリンクできる特別な .o ファイルを作成すれば、パッチ領域を拡大できます。rtc_patch_area(1) マニュアルページを参照してください。
    dbx の実行時に 8M バイト制限に達すると、大きすぎる読み込みオブジェクト (メインプログラムや共有ライブラリ) が報告され、その読み込みプロジェクトに必要なパッチ領域値が出力されます。
    最適な結果を得るには、実行可能ファイルや共有ライブラリ全体に特別なパッチオブジェクトファイルを均等に分散させ、デフォルトサイズ (8M バイト) かそれよりも小さいサイズを使用します。dbx が必要とする必要値の 10 % から 20 % の範囲を超えてパッチ領域を追加しないでください。たとえば、dbx.out に 31M バイトを要求する場合は、rtc_patch_area スクリプトで作成したそれぞれのサイズが 8M バイトのオブジェクトファイルを 4 つ追加し、実行可能ファイル内でそれらをほぼ均等に分割します。
    dbx の実行時に、実行可能ファイルに明示的なパッチ領域が見つかると、パッチ領域になっているアドレス範囲が出力されるので、リンク回線に正しく指定することができます。

  4. 読み込みオブジェクトが大きい場合は、小さい読み込みオブジェクトに分割します。

    実行ファイルや大きなライブラリ内のオブジェクトファイルを小さいオブジェクトファイルグループに分割します。それらを小さいパーツにリンクします。大きいファイルが実行可能ファイルの場合、小さい実行可能ファイルと共有ライブラリに分割します。大きいファイルが共有ライブラリの場合、複数の小さいライブラリのセットに再編します。
    この方法では、dbx により、異なる共有オブジェクト間でパッチコード用の領域を探すことができます。

  5. パッド .so ファイルを追加します。

    この処置は、プロセスの起動後に接続する場合にのみ必要です。
    実行時リンカーによるライブラリの配置間隔が狭すぎてライブラリ間にパッチ領域を作成できない場合があります。RTC を on にして dbx が実行可能ファイルを起動すると、dbx は実行時リンカーに対して共用ライブラリ間に新たなギャップを挿入するよう指示しますが、実行時検査を有効にして dbx で起動されていないプロセスに接続しても、ライブラリ間が狭すぎて対応できません。
    この場合 (そしてプログラムを dbx で起動できない場合) は、rtc_patch_area スクリプトで共有ライブラリを作成し、他の共有ライブラリ間でプログラムにリンクしてください。詳細については、rtc_patch_area(1) マニュアルページを参照してください。

RTC エラー

RTC で報告されるエラーは、通常はアクセスエラーとリークの 2 種類があります。

アクセスエラー

アクセス検査がオンのとき、RTC による検出と報告の対象になるのは次のタイプのエラーです。

不正解放 (baf) エラー

意味 : 割り当てられたことのないメモリーを解放しようとした。

考えられる原因 : free() または realloc() にヒープデータ以外のポインタを渡した。

 例 :

 char a[4];

 char *b = &a[0];

 

 free(b);           /* 不正解放 (baf) */

重複解放 (duf) エラー

意味 : すでに解放されているヒープブロックを解放しようとした。

考えられる原因 : 同じポインタを使用して free() を 2 回以上呼び出した。C++ では、同じポインタに対して "delete" 演算子を 2 回以上使用した。

例 :

 char *a = (char *)malloc(1);

 free(a);

 free(a);               /* 重複解放 (duf) */

境界整列を誤った解放 (maf) エラー

意味 : 境界合わせされていないヒープブロックを解放しようとした。

考えられる原因 : free() または realloc() に正しく境界合わせされていないポインタを渡した。malloc によって返されたポインタを変更した。

例 :

 char *ptr = (char *)malloc(4);

 ptr++;

 free(ptr);               /* 境界整列を誤った解放 (maf) */

境界整列を誤った読み取り (mar) エラー

意味 : 適切に境界合わせされていないアドレスからデータを読み取ろうとした。

考えられる原因 : ハーフワード、ワード、ダブルワードの境界に合わせられていないアドレスから、それぞれ 2 バイト、4 バイト、8 バイトを読み取った。

例 :

       char *s = "hello world";

       int *i = (int *)&s[1];

       int j;

 

       j = *i;           /* 境界整列を誤った読み取り (mar) */

境界整列を誤った書き込み (maw) エラー

意味 : 適切に境界合わせされていないアドレスにデータを書き込もうとした。

考えられる原因 : ハーフワード、ワード、ダブルワードの境界に合わせられていないアドレスに、それぞれ 2 バイト、4 バイト、8 バイトを書き込んだ。

例 :

 char *s = "hello world";

 int *i = (int *)&s[1];

 

 *i = 0;           /* 境界整列を誤った書き込み (maw) */

メモリー不足 (oom) エラー

意味 : 利用可能な物理メモリーより多くのメモリーを割り当てようとした。

考えられる原因 : プログラムがこれ以上システムからメモリーを入手できない。oom エラーは、malloc() からの戻り値が NULL かどうか検査していない (プログラミングでよく起きる誤り) ために発生する問題の追跡に役立ちます。

例 :

       char *ptr = (char *)malloc(0x7fffffff);

       /* メモリー不足 (oom), ptr == NULL */

非割り当てメモリーからの読み取り (rua) エラー

意味 : 存在しないメモリー、割り当てられていないメモリー、マップされていないメモリーからデータを読み取ろうとした。

考えられる原因 : ストレイポインタ (不正な値を持つポインタ)、ヒープブロック境界のオーバーフロー、すでに解放されたヒープブロックへのアクセス。

例 :

 char c, *a = (char *)malloc(1);

 c = a[1];  /* 非割り当てメモリーからの読み取り (rua) */

非初期化メモリーからの読み取り (rui) エラー

意味 : 初期化されていないメモリーからデータを読み取ろうとした。

考えられる原因 : 初期化されていない局所データまたはヒープデータの読み取り。

例 :

 foo()

 {   int i,  j;

 j = i;  /* 非初期化メモリーからの読み取り (rui) */

 }

読み取り専用メモリーへの書き込み (wro) エラー

意味 : 読み取り専用メモリーにデータを書き込もうとした。

考えられる原因 : テキストアドレスへの書き込み、読み取り専用データセクション

(.rodata) への書き込み、読み取り専用として mmap されているページへの書き込み。

例 :

 foo()

 {  int *foop = (int *) foo;

 *foop = 0;/* 読み取り専用メモリーへの書き込み (wro) */

 }

非割り当てメモリーへの書き込み (wua) エラー

意味 : 存在しないメモリー、割り当てられていないメモリー、マップされていないメモリーにデータを書き込もうとした。

考えられる原因 : ストレイポインタ、ヒープブロック境界のオーバーフロー、すでに解放されたヒープブロックへのアクセス。

例 :

 char *a = (char *)malloc(1);

 a[1] = `\0';/* 非割り当てメモリーへの書き込み (wua) */

メモリーリークエラー

リーク検査をオンにしておくと、RTC では次のエラーが報告されます。

ブロック中のアドレス (aib)

意味: メモリーリークの可能性がある。割り当てたブロックの先頭に対する参照はないが、そのブロック内のアドレスに対する参照が少なくとも 1 つある。

考えられる原因: そのブロックの先頭を示す唯一のポインタが増分された。

例:

 char *ptr;

 main()

 {

    ptr = (char *)malloc(4);

    ptr++;	 /* Address in Block */

 }

レジスタ中のアドレス (air)

意味: メモリーリークの可能性がある。割り当てられたブロックが解放されておらず、そのブロックに対する参照がプログラムのどこにもないが、レジスタには参照がある。

考えられる原因: コンパイラがプログラム変数をメモリーではなくレジスタにだけ保存している場合にこのエラーになる。最適化をオンにしてコンパイラを実行すると、ローカル変数や関数パラメタにこのような状況がよく発生する。最適化をオンにしていないのにこのエラーが発生する場合は、メモリーリークが疑われる。ブロックを解放する前に、割り当てられたブロックに対する唯一のポインタが範囲外を指定するとメモリーリークになる。

例:

 if (i == 0) {

        char *ptr = (char *)malloc(4);

        /* ptr is going out of scope */

 }

   /* Memory Leak or Address in Register */

メモリーリーク (mel) エラー

意味 : 割り当てられたブロックが解放されておらず、そのブロックへの参照がプログラム内のどこにも存在しない。

考えられる原因 : プログラムが使用されなくなったブロックを解放しなかった。

例 :

char *ptr;

     ptr = (char *)malloc(1);

     ptr = 0;

 /* メモリーリーク (mel) */


サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.
ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引