C迷路指針の詳細

3709 ワード

本文はC言語の迷路指針を詳しく述べ、その概念、原理と検出方法を分析した.皆さんの参考にしてください.具体的には以下の通りです.
一般に、コンピュータプログラミングの分野では、迷路ポインタ、またはサスペンションポインタ、野ポインタと呼ばれ、合法的なオブジェクトを指さないポインタを指す.
ポインタは、指向されたオブジェクトが解放または回収されたが、ポインタが回収されたメモリアドレスを指すように変更されていない場合、迷路ポインタと呼ばれる.OSが解放されたメモリを別のプロセスに再割り当てし、元のプログラムが現在の迷路ポインタを再参照すると、予想できない結果が発生します.このとき、迷路ポインタが指すメモリには、まったく異なるデータが含まれているからです.通常、元のプログラムが迷路ポインタが指すメモリアドレスにデータを書き込み続けると、元のプログラムに関連しないデータが破損し、予期せぬプログラムエラーを引き起こす.このタイプのプログラムエラーは、問題の原因を見つけにくく、通常はセグメントエラー(Linuxシステム)と一般保護エラー(Windowsシステム)を引き起こす.オペレーティングシステムのメモリディスペンサが上書きされたデータ領域を再割り当てすると、システムの安定性に影響を与える可能性があります.
一部のプログラミング言語では、初期化されていないポインタの存在を許可します.このようなポインタは野ポインタです.野ポインタによるエラーは迷路ポインタとよく似ていますが、野ポインタの問題は発見されやすいです.
迷路ポインタの成因
多くのプログラミング言語(C言語など)でメモリからオブジェクトを削除したり、戻ってきたときにスタックフレームを削除したりした場合、関連するポインタの値は変更されません.ポインタは元のメモリアドレスを指し、参照が削除されても他のプロセスで使用されている可能性があります.
次のように、直接的な例を示します.

{
  char *cp = NULL;
  /* ... */
  {
    char c;
    cp = &c;
  } /* c falls out of scope */     
   /* cp is now a dangling pointer */
}

上記の問題の解決策は、この部分のプログラムが終了する直前にCPに0値(NULL)を付与することである.もう1つの方法は、CPが初期化されないまで使用されないことを保証することである.
迷路ポインタは、malloc()とfree()ライブラリ呼び出しを混在させて頻繁に表示されます.ポインタが指すメモリが解放されると、ポインタは迷路になります.前の例と同様に、このエラーを回避する方法は、参照を解放した後、ポインタの値をNULLにリセットすることです.以下に示します.

#include 
{
  char *cp = malloc ( A_CONST );
  /* ... */
  free ( cp );   /* cp             */
  cp = NULL;    /* cp         */
  /* ... */
}

スタックに基づいて割り当てられたローカル変数のアドレスを返すと、呼び出された関数が戻ると、これらの変数に割り当てられた空間が回収され、「ゴミ値」があるという一般的なエラーがあります.

int * func ( void )
{
  int num = 1234;
  /* ... */
  return #
}

funcが呼び出されてからしばらくして、ポインタからnumの値を読み出してみても、正しい値(1234)を返すことができますが、次の関数呼び出しは、元のスタックがnumに割り当てられた空間を上書きします.このとき、このポインタからnumの値を読み出すと正しくありません.numを指すポインタを正しいnum値に戻すには、変数をstaticとして宣言する必要があります.
野指針の発生
野ポインタとは、まだ初期化されていないポインタのことです.厳密には、プログラミング言語では、各ポインタは初期化前に野ポインタである.
通常、初期化されていないときにポインタを使用すると問題が発生します.ほとんどのコンパイラは、この問題を検出し、ユーザーに警告します.

int f(int i)
{
  char* cp;  //cp     
  static char* scp; //scp      ,          0       
//                 
}

迷路ポインタによるセキュリティ・ホール
キャッシュオーバーフローエラーのように、迷路ポインタ/野ポインタのようなエラーは、セキュリティ・ホールを招くことが多い.たとえば、1つのポインタが虚関数を呼び出すために使用される場合、vtableポインタが上書きされているため、異なるアドレス(利用されるコードを指す)にアクセスする可能性があります.あるいは、ポインタがメモリに書き込まれると、他のデータ構造が破損する可能性があります.このポインタが迷路ポインタとなると、このメモリが読み取り専用であっても、情報の漏洩(興味のあるデータが次のデータ構造に格納、このメモリに適切に割り当てられている場合)やアクセス権の増加(現在使用できないメモリが安全検出に使用されている場合)を招く.
迷路ポインタの誤りを避ける
迷路ポインタを避けるには、スマートポインタ(Smart pointer)を使うという人気のある方法があります.スマートポインタは、参照カウントを使用してオブジェクトを回収します.他のいくつかの技術にはtombstone法とlocks−and−keys法が含まれる.
さらに、DieHardメモリディスペンサを使用して、他のメモリエラー(不正または2回のメモリ解放)のような迷路ポインタエラーを仮想的に除去できます.
もう1つの方法は、CとC++の標準メモリ割り当て関数に代わる保守的なゴミ回収方法です.この方法は迷路ポインタの誤りを完全に解消し,メモリ解放関数を除去することによってゴミ回収器に代わってオブジェクトの回収を完了する.
Java言語では、メモリを明確に再割り当てするメカニズムがないため、迷路ポインタのようなエラーは発生しません.また、ゴミ回収器は、オブジェクトの参照数がゼロの場合にのみメモリを再割り当てます.
迷路ポインタの検出
迷路ポインタを発見するために、ポインタが指すメモリ空間が解放されると、直ちにポインタを空のポインタまたは不正なアドレスに設定する一般的なプログラミング技術がある.空のポインタが再参照されると、プログラムはすぐに停止し、データの破損や予期せぬ結果を回避します.これにより、次のプログラミングプロセスで発生するエラーが容易に発見され、解決されます.この技術は,このポインタが複数コピーされている場合には本来の役割を果たすことができない.
いくつかのデバッガは、0 xDEADBEEF(Microsoft's Visual C/C++デバッガ)のような解放されたデータを自動的に特定のモードで上書きし、例えば、どのタイプに応じて0 xCC、0 xCD、または0 xDDを採用するかを解放する.この方法は,データを無駄にすることによって,解放されたデータの再使用を防止する.この方法の役割は非常に顕著である(このモードは、プログラムが解放されたばかりのメモリを区別するのに役立つ).
Valgrind、Mudflap、またはLLVMなどのツールは、迷路ポインタの使用を検出するために使用できます.
総じて,迷路ポインタはCプログラムのセキュリティに大きな影響を及ぼし,Cプログラマーが慎重に処理しなければならない問題である.本文の述べたことは皆さんのCプログラムの設計に対して一定の参考価値があると信じています.