0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

メモリリーク検出(Sanitizer)

Last updated at Posted at 2024-10-24

背景

メモリリークのチェックでValgrindを使用したが動作が重く、解決方法を探していたところgccに組み込まれている機能で動的にメモリリークと不正メモリアクセスをチェックできることが分かったのでまとめる。

LeakSanitizerの概要

  • メモリリークの動的チェックツール
  • gcc/g++のコンパイルオプションに設定するだけで使用できる
  • Valgrindより軽い
  • Sanitizerにはリークチェック以外にも色々と機能がある

リークチェックの例

サンプルコード

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

int main(void)
{
    char* foo = (char*)malloc(sizeof(char));
    return 0; // mallocしたメモリをfreeせずにプログラム終了
}

サンプルコードを下記のコンパイルオプションでビルドする。

$ gcc gcc -fsanitize=leak -g -o main main.c
# -gオプションは出力結果にファイル名とコード行数を表示するために必要

ビルド後出力されたelfファイルを実行すると以下のように出力される。
#1 0x55a32e84b17e in main /home/jkano/main.c:6の部分で解放されていないメモリが割り当てられた場所を教えてくれる。

$ ./main

=================================================================
==1966==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1 byte(s) in 1 object(s) allocated from:
    #0 0x7fab9071b302 in __interceptor_malloc ../../../../src/libsanitizer/lsan/lsan_interceptors.cpp:75
    #1 0x55a32e84b17e in main /home/jkano/main.c:6
    #2 0x7fab90508d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

メモリ不正アクセスチェックの例

サンプルコード

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

int main(void)
{
    char* foo = (char*)malloc(sizeof(char) * 2);
    foo[2] = 0x01; // 確保していない3番目の要素にアクセス
    return 0;
}

サンプルコードを下記のコンパイルオプションでビルドする。

gcc -fsanitize=address -g -o main main.c

ビルド後出力されたelfファイルを実行すると以下のように出力される。
#0 0x564ce0e501fe in main /home/jkano/sanitizer/main.c:7の部分でメモリの不正アクセスが行われた場所を教えてくれる。

=================================================================
==5108==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000012 at pc 0x564ce0e501ff bp 0x7fff4cbbad30 sp 0x7fff4cbbad20
WRITE of size 1 at 0x602000000012 thread T0
    #0 0x564ce0e501fe in main /home/jkano/sanitizer/main.c:7
    #1 0x7f5e9d6d5d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #2 0x7f5e9d6d5e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #3 0x564ce0e500e4 in _start (/home/jkano/sanitizer/main+0x10e4)

0x602000000012 is located 0 bytes to the right of 2-byte region [0x602000000010,0x602000000012)
allocated by thread T0 here:
    #0 0x7f5e9d988887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x564ce0e501be in main /home/jkano/sanitizer/main.c:6
    #2 0x7f5e9d6d5d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/jkano/sanitizer/main.c:7 in main
(以下略)

注意

上記メモリ不正アクセスの例だと、メモリの不正アクセスが行われた時点でプログラムが止まってしまうが、以下を実施することでプログラムを実行し続けることが可能。

  • コンパイルオプションの追加:-fsanitize-recover=address
    • 例:$ -fsanitize=address -fsanitize-recover=address -g -o main main.c
  • 環境変数の設定:ASAN_OPTIONS=halt_on_error=0
    • 例:$ export ASAN_OPTIONS=halt_on_error=0

補足

Sanitizerには以下5種類あり、様々な動的コード分析が行える。

  • AddressSanitizer メモリ破損チェック
  • LeakSanitizer メモリリークチェック
  • ThreadSanitizer スレッド間でのデータ競合チェック
  • UndefinedBehaviorSanitizer 未定義動作の実行チェック
  • MemorySanitizer 未初期化メモリの参照チェック

参考

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?