SOLIDでは、アドレスバグの代表的なものである、スタックオーバーフローの自動検出が可能です。スタックオーバーフローは異常な多重割り込みや、内部変数等のスタック情報の増加が原因で、設計時の想定以上のスタックを消費してしまい、スタックメモリの上限を突き抜けて他の領域にスタックを積んで(データを書き込んで)しまうという、組込みではよく目にするバグです。
SOLIDでは、ビルド時にツールチェーンで指定されたスタックメモリのアドレス範囲をツール側が把握しているので、デバッガを接続した状態でプログラムが動作中にスタックオーバーフローが発生すると、それを直ちに検出します。
スタックオーバーフローが発生した場合は、図1-1①のように、”Data Abort Exception caused by stack overflow” とデバッグ例外ウインドウに表示し、プログラムの続行を中断(ブレーク)します。またその時にRTOSビューワー(図1-1②)ではタスクに割り当てられたスタックの消費量をビジュアルに表示するので、どのタスクがスタックオーバーフローの要因になったのかを容易に知ることができます。
スタックオーバーフローはソースプログラムの静的解析により検出する事は困難なので、このような自動検出機能は大変有効です。しかもSOLIDでは特別な設定や、実行時間のオーバーヘッド無しでスタックオーバーフローが検出できるというところも大きな利点といってよいでしょう。
図1-1スタックオーバーフロー検出時のデバッガ画面表示
プログラムのコード領域へ不当書き込みが起きると、本来動作するはずのプログラムコードが変わってしまうため「プログラムが暴走」してしまいます。不具合現象が発生したとき、それが暴走によるものかどうかを判断することは容易ではありませんし、暴走しているためにソフトウエアの流れを追う事すら難しいというのが実態です。
また不当書き込みによりコード領域を破壊してしまうような不具合は、ソフトウエアの規模が大きくなるにつれて、「他人の開発しているモジュールのコードを破壊する」という、自分では気づきにくいやっかいなバグです。
そこでSOLIDでは、プロセッサのアクセス例外検出機能を利用して不当アクセスを検出できるようにしました。以下がその動作概要です。
まず作成されたプログラムは、ビルド時に設定したプログラムのセクション情報に従い、ロードモジュールを生成するときに、
.text、.rodata、.data、.bss
という属性の異なるセクションに分けられます(図1-2)。
各セクションは
.text は実行コードなので、「ライト不可」、「実行可能」
.rodata は read only データだから、「ライト不可」、「実行不可」
.data や .bss は、読み書き可能データだから、「ライト可」、「実行不可」
という属性を持っており、セクションの属性に従いSOLIDがMMUの設定を行います。
MMUによりライト不可と設定されたコード領域へのライト動作が発生した場合には、メモリが書き換えられる前にプロセッサがアドレス例外を起こすので、SOLIDデバッガと連動してバグ発生を検出しプログラムがブレークします。
実行不可領域でのプログラム実行も同様に検出します。
また、セクションの存在しないアドレス領域には物理メモリを割り当てないようにSOLIDがMMUを設定するので、リード・ライトや命令フェッチ動作のいずれでもプロセッサ例外が発生し、上記同様にバグを自動検出します。
図1-2. ビルド時に設定したセクション情報に従い、SOLIDがMMUのメモリ属性を設定
配列として確保したメモリ領域に、配列サイズを超えてアクセスしようとした場合、SOLIDが自動的にバグを検出します。
簡単な配列オーバーランの例:
char buf[10];
for (i=0; i<=10; i++) {
buf[i]=i;
}
この例では10個の配列に対してこのforループを実行するとiが0~10まで、11個のデータを書き込むというバグが含まれています。このプログラムをデバッガを接続した状態で実行すると、11個目のデータを書き込もうとする直前に、SOLIDがバグを検出して”Out of bound access”とサニタイザウインドウにアドレスバグの要因を表示しプログラムをブレークします(図1-3①)。このとき、アクセスしようとしていた近辺のメモリ内容と、当該命令を各々メモリウインドウ(図1-3②)と、ソースウインドウ(図1-3③)でバグの箇所を分かりやすく表示します。
図1-3.配列オーバーランを自動検出した際のデバッガ表示
配列オーバーランとしては、上記の他にもmemcpy()のようなメモリブロック操作命令に対してもバグがあれば自動検出が可能です。
この例で示した配列オーバーランは、SOLIDのアドレスサニタイザという専用の実行時バグ検出の仕組みを用いているので、ユーザーが意識的にブレークポイントを設定したり、検出対象の変数を指定する必要は全くありません。SOLIDのビルド構成を「アドレスサニタイザモード」に指定するだけの簡単な操作でアドレスサニタイザが使用でき、バグを探し出す時間を大幅に短縮可能です。
ただし、アドレスサニタイザモードを使用する場合、バグ検出のためのランタイムをユーザコード中に埋め込んで動作させるため、実行時間および使用メモリ(プログラムおよびワークRAM)にオーバーヘッドが発生します。
このアドレスサニタイザの動作の詳しい仕組みについては、第二回で解説します。