clang/gccに組み込まれたAddressSanitizer/LeakSanitizerでメモリエラーを捕捉する

C/C++でのユニットテストによるメモリリーク検出 - 千里霧中の補足。

メモリエラーの検出方法についてだけれど、最近のclangやgccだと、AddressSanitizerという動的解析ツールが組み込まれており、それを活用できる。

使用する場合はコンパイラオプション「-fsanitize=address」「-fsanitize=leak」等を指定する。

題材

例えば以下のコードを対象にする。

//main.c
#include <stdio.h>
#include <stdlib.h>

void hoge(void)
{
        int *a_buff = (int *)malloc(5 * sizeof(int));
        a_buff[10] = 8;
}

int main(void)
{
        printf("test\n");
        hoge();
        return 0;
}


これを普通にコンパイルして実行すると「test」が表示されるだけで、特にエラーなどは検出されない。

AddressSanitizerでの不正なメモリアクセスの検出

一方で、以下のオプションでコンパイルして、AddressSanitizerを有効化する。

gcc -g -fsanitize=address main.c

これで実行すると、「a_buff[10] = 8」の実行タイミングで以下のエラーメッセージが出力されるようになる。

==23801==ERROR: AddressSanitizer: heap-buffer-overflow on address 
略
==23801==atos returned: An admin user name and password is required to enter Developer Mode.
    #0 0x113d63d4d in hoge (*****/./a.out+0x110000d4d)
    #1 0x113d63e04 in main (*****/./a.out+0x110000e04)
    #2 0x1ff199451ac in start (/usr/lib/system/libdyld.dylib+0x35a0)
    #3 0x0  (<unknown module>)
略
SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 hoge
Shadow bytes around the buggy address:
以下略

LeakSanitizerでのメモリリークの検出

次に以下のオプションでコンパイルして、LeakSanitizerを有効化する。

gcc -g -fsanitize=leak main.c

これを実行すると、アプリケーション終了時点で以下のエラーメッセージが出力されるようになる。

==6316==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 20 byte(s) in 1 object(s) allocated from:
略