アドレスサニタイザ
概要
アドレスサニタイザは、Clangコンパイラとランタイム、IDEが連携し不正なメモリアクセスを実行時に検出する機能です。 本機能では、以下のメモリアクセス違反が検出可能です。
ローカル変数 (スタック領域) の範囲外アクセス
グローバル変数に対しての範囲外アクセス
動的に確保 (malloc) したメモリに対しての範囲外アクセス
freeしたメモリ領域へのアクセス
二重free
使い方
実際に、Starter Kitに付属のアドレスサニタイザデモ ボード名-demo-sanitizer
を動作させてみます。
アドレスサニタイザデモについて
本サンプルには、malloc()
で確保したバッファの範囲外アクセスと、free()
したバッファへのメモリアクセスの2種類のバグが入っています。
この程度であれば、対象となるプログラムに大きな影響を与える事なく動作を継続できる可能性が高いですが、場合によっては重大なクラッシュを引き起こす事もあります。
実際に、デフォルトの Debug 構成 (アドレスサニタイザ無効) でビルド、実行すると、特に問題は発生せずプログラムが動作します。 これらのバグを、アドレスサニタイザを有効にしてビルドする事で、自動的に検出してみましょう。
構成の変更と実行
サンプルアプリケーションの実行 を参考に、ボード名-demo-sanitizer
を開き、
ビルドの構成を Debug_tasan に変更します。
ビルドと実行
メニューの
でプロジェクトをビルドし、 で実行します。バグの検出
実行後、確保したバッファの範囲外をアクセスする直前に、自動的にプログラムが停止し、問題のあるソース行がハイライト表示されます。 また、デバッグ例外 ウィンドウには、検出されたバグの種類やアクセス先のアドレス、アクセスサイズ、アクセスタイプ (ReadまたはWrite)、 タスクID、エラーの発生する実行アドレス (PC) が表示されます。
これらの情報から、実行アドレス0xf0c003c0で、1バイトの書込みアクセスが0xf0ca3838に対して発生し、それがメモリの範囲外アクセス である事がわかりました。
注釈
本機能では、バグを引き起こす操作 (上記の例では strb
命令) が実行される前にプログラムが停止します。
さらに実行を再開すると、次は free()
したバッファへのアクセスが発生する直前で停止します。
ここでも デバッグ例外 ウィンドウなどの情報から、実行アドレス0xf0c003f4で、1バイトの書込みアクセスが0xf0ca3438に対して発生し、それが既にfreeされたメモリに対してのアクセス である事がわかります。
アドレス設定と注意点
アドレスサニタイザで使用するメモリ領域を設定するには、メモリマップデザイナで以下の項目を設定してください。
- Monitoring address
アドレスサニタイザで監視する仮想アドレスの先頭 (コードやデータが存在する領域を指定します。I/O領域は指定しないでください。また、スタックの領域は必ず含めてください。)
- Monitoring size
監視するサイズ (バイト単位)
- Shadow memory address(Physical)
シャドウメモリの物理アドレスの先頭 1
- Shadow memory address(Virtual)
シャドウメモリの仮想アドレスの先頭
- 1
シャドウメモリは、アドレスサニタイザに必要な追加のメモリ領域で、監視用の補助情報が格納されています。 通常、監視するメモリ領域の8分の1のサイズが自動で追加されますので、シャドウメモリのサイズを指定する必要はありません。
監視領域について
以下の図の例のように、コードやデータ領域以外にも、必ずスタックを監視する範囲に含めてください。 アドレスサニタイザが有効になっている場合、スタックに対する監視用のデータを実行時にシャドウメモリに書き込むため、 スタックが監視範囲から外れていると、関数の先頭でデータアボート例外が発生してしまいます。
アドレス設定について
アドレスサニタイザの動作上の制限により、シャドウメモリを bit28=1 となるアドレス、または0x10000000以下に設定しないでください。 すなわち 0x3FFFFFFF以下、0x5xxxxxxx, 0x7xxxxxxx には設定できません。推奨アドレス (Virtual) は 0x40000000 です。 物理メモリのアドレスに関しては制限はありません。