1. ホーム
  2. c

[解決済み] すべての変数が使用されている場合、スタック、マローク、(最近の)フリーは行われていない。

2022-02-08 14:50:14

質問

この関数を呼び出すと

int within(struct key *node, int *value) {                      
  int length = len(node);                                       
  if ((value <= node[length-1].data) && (value >= node[0].data)) // Problematic line
    return 0;                                                   
  else if (value > node[length-1].data)                         
    return 1;                                                   
  else if (value < node[0].data)                                
    return -1;                                                  
}                                                               

Valgrindはこのエラーメッセージを発生させます。

アドレス0x51f60a0はスタックされていないか、マックされていないか、(最近)解放されました。

valuenode の変数が正しい値である。すべての変数が使用されています。メモリ管理はどうなっているのでしょうか?もし、このスニペットで状況がはっきりしないのであれば、教えてください。

解決方法は?

メッセージ Address 0x51f60a0 is not stack'd, malloc'd or (recently) free は通常、より大きな Valgrind エラーメッセージの一部でしかありません。

このValgrindのエラーメッセージは、通常このようなものです。

Invalid read of size 4
   at 0x40F6BBCC: (within /usr/lib/libpng.so.2.1.0.9)
   by 0x40F6B804: (within /usr/lib/libpng.so.2.1.0.9)
   by 0x40B07FF4: read_png_image__FP8QImageIO (kernel/qpngio.cpp:326)
   by 0x40AC751B: QImageIO::read() (kernel/qimage.cpp:3621)
   Address 0xBFFFF0E0 is not stack'd, malloc'd or free'd

または

Invalid read of size 8
   at 0x40060E: free_adj_list (main.c:9)
   by 0x400844: main (main.c:65)
 Address 0x4c1d170 is 16 bytes inside a block of size 24 free'd
   at 0x4A04D72: free (vg_replace_malloc.c:325)
   by 0x400609: free_adj_list (main.c:8)
   by 0x400844: main (main.c:65)

エラーメッセージの読み方

メッセージの最初の部分は、何が問題だったのかを示し("Invalid read of size 4"は、アクセスしてはいけないメモリーアドレスから読み込もうとしたという意味)、その後にエラーが発生したバックトレースが続きます。

バックトレースの後に、アクセスしようとしたメモリアドレスの詳細が表示されます。Valgrind はここで、あなたが何を言いたかったのか、そのアドレスがそうであるかどうかを調べ、推測します。

  • アクセス可能なメモリ部分のすぐ外側(つまり、プログラムが バッファオーバーラン ). メッセージの例は次のとおりです。 Address 0x1002772ac is 4 bytes after a block of size 12 alloc'd
  • 前に解放されたメモリブロックの内部で(つまり、あなたのプログラムは 解放された後にメモリを使用した ); 例を挙げます。 Address 0x4c1d170 is 16 bytes inside a block of size 24 free'd

そして、これらのメッセージの後に、言及されたメモリをどこで割り当てたのか、あるいは解放したのかを示す2番目のバックトレースが続きます。

しかし、メッセージ Address 0x51f60a0 is not stack'd, malloc'd or (recently) free'd は、Valgrind があなたが何をしようとしたのか推測できなかったことを意味します。あなたは 0x51f60a0 のメモリにアクセスしようとしましたが、そのアドレスは最近解放されていませんし、あなたが割り当てたメモリの他の部分の近くにもありません。ですから、この場合のエラーはバッファオーバーランでもなければ、use-after-free エラーでもないということを、あなたは合理的に確認することができます。

このようなエラーのデバッグ方法

つまり、0x51f60a0は多少なりともランダムなメモリアドレスであると推測されます。この原因としては、主に2つの可能性が考えられます。

  • 参照解除したポインタに初期化されていない値が含まれていた場合。 Use of uninitialised value のエラーメッセージが表示されます。
  • ポインタとして意図していない値をデリファレンスした場合(例:プログラム内の無関係な計算結果である可能性があり、何らかの方法でその値をポインタに書き込んで、後で使用した場合

これらとは別に、もちろん、エラーが実際には何らかのバッファオーバーランやuse-after-freeであるにもかかわらず、Valgrindがそれを検出できなかったという可能性も残っています。

プログラム中のこのエラーのデバッグ方法

問題を絞り込む一つの方法は、Valgrindでアプリケーションを起動することだと思います。 GDBで を使用して、具体的にどのようなメモリアクセスがエラーを引き起こすのかを調べます。 node が悪いのか?それとも node[length-1] が悪いのか?は node[0] のようなものです。) そして、その悪い値がそもそもどのようにそこに来たのかを調べます。