アドレスサニタイザー、またはvalgrindが機能しない場合の対処方法

困難な状況がありました。 Goで記述されたプロジェクトでcgoを介して積極的に使用されるCで記述されたコードがあります。 ある時点で、プログラムはmallocからのエラーでクラッシュし始めました:segfault、次にメモリ破損。



論理的思考:memcheckを使用してvalgrindを実行し、誰が老人を越えて地獄に乗り込み、無効なメモリに侵入するかをチェックする必要があります。 ただし、go buildから受け取ったバイナリにvalgrindをフィードしようとしても失望するだけです-単純なHello Worldであっても、valgrindは数百のエラーを発生させ、開発者を既知の座標に送ります(ネタバレ:「 プログラムを修正してください! 」)。



これは、goランタイムが非常に具体的であり、Cのランタイムとは大きく異なるという事実によるものです(詳細は、リクエスト「golang valgrind」で簡単に見つけることができます)。



では、何が起こっているのかをどのように把握するのでしょうか?



グーグルでよく調べてみると、gcc(および、ちなみにclang)には非常に便利なツール-Address Sanitizerがあることがわかりました 。 valgrind(少なくとも解放されたメモリの使用、オーバーフロー、リークの使用をキャッチできる)を行うことができ、同時に外部ユーティリティを使用せずに自動的にバイナリに統合できるという点で便利です。 しかし、主なことは、Goランタイムで干渉せずにCGoでCコードを安全にデバッグできることです(実際、Go開発者自身がこのツールの使用を推奨しています)。



使い方は?



  1. gccバージョンが4.8以上であることを確認してください。
  2. フラグ-fsanitize = addressを使用してプログラムをコンパイルします(gccのドキュメントには、さらに多くのサニタイザーが記載されています。 こちらを参照してください )。 このフラグは、アセンブリ中とリンク中の両方に追加する必要があります(CFLAGSとLDFLAGSの両方で)。
  3. プログラムを実行し、消毒剤のマルチカラーの結論をお楽しみください。


検証のために、10個の整数にスペースを割り当てるが、11個(test.c)を埋める簡単なプログラムを作成しました。



#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int *m = (int *) malloc(10 * sizeof (int)); for (int i = 0; i < 11; i++) { m[i] = i; } return 0; }
      
      





これを-fsanitize = addressでコンパイルします。開始後、次のように表示されます。



 webconn@webconn-laptop:~/Projects/Testing/C/Sanitizer$ gcc -o ./main ./test.c -fsanitize=address webconn@webconn-laptop:~/Projects/Testing/C/Sanitizer$ ./main ================================================================= ==18098==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000dff8 at pc 0x557945c74922 bp 0x7fff94c67d40 sp 0x7fff94c67d38 WRITE of size 4 at 0x60400000dff8 thread T0 #0 0x557945c74921 in main (/home/webconn/Projects/Testing/C/Sanitizer/main+0x921) #1 0x7fea6440b2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0) #2 0x557945c747a9 in _start (/home/webconn/Projects/Testing/C/Sanitizer/main+0x7a9) 0x60400000dff8 is located 0 bytes to the right of 40-byte region [0x60400000dfd0,0x60400000dff8) allocated by thread T0 here: #0 0x7fea6484ad28 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc1d28) #1 0x557945c748c8 in main (/home/webconn/Projects/Testing/C/Sanitizer/main+0x8c8) #2 0x7fea6440b2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0) SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/webconn/Projects/Testing/C/Sanitizer/main+0x921) in main Shadow bytes around the buggy address: 0x0c087fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c087fff9bf0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00[fa] 0x0c087fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==18098==ABORTING
      
      





実際には、色で強調表示されたままです。



カラーでの出力(PNG、78.5 KB)
画像



これがcgoで機能するように、Cコードを接続するときに適切な特別なコメントを追加しました(ドットの場所に、有用なフラグとディレクティブがあります)。



 /* #cgo linux LDFLAGS: ... -fsanitize=address #cgo linux CFLAGS: ... -fsanitize=address ... */ import "C"
      
      





これは望ましい結果をもたらしました-Cで書かれたモジュールはメモリ問題のデバッグ情報を提供しますが、Goランタイムの静かな生活を妨げません。



実際、Go開発者自身は、そのような状況でSanitizerを使用することを推奨しています。



この情報が誰かに役立つことを願っています。



UPD:もちろん、-gフラグを追加すると、出力はさらに読みやすくなります。

-gフラグを使用したコンパイル後の出力
 webconn@webconn-laptop:~/Projects/Testing/C/Sanitizer$ ./main ================================================================= ==12266==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000dff8 at pc 0x55d4f8d03922 bp 0x7ffc10a57370 sp 0x7ffc10a57368 WRITE of size 4 at 0x60400000dff8 thread T0 #0 0x55d4f8d03921 in main /home/webconn/Projects/Testing/C/Sanitizer/main.c:14 #1 0x7fa688d282b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0) #2 0x55d4f8d037a9 in _start (/home/webconn/Projects/Testing/C/Sanitizer/main+0x7a9) 0x60400000dff8 is located 0 bytes to the right of 40-byte region [0x60400000dfd0,0x60400000dff8) allocated by thread T0 here: #0 0x7fa689167d28 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc1d28) #1 0x55d4f8d038c8 in main /home/webconn/Projects/Testing/C/Sanitizer/main.c:11 #2 0x7fa688d282b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0) SUMMARY: AddressSanitizer: heap-buffer-overflow /home/webconn/Projects/Testing/C/Sanitizer/main.c:14 in main Shadow bytes around the buggy address: 0x0c087fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c087fff9bf0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00[fa] 0x0c087fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==12266==ABORTING
      
      








All Articles