ソフトウェア開発者が困っていること
ソフトウェアの大規模化にともない、バグ探しが大掛かりになって大変
ソフトウェアの規模が大きくなると、複数メンバーによる分担開発
はもちろん、協力会社に委託をして共同開発するというスタイル

組込み初実行時アドレスバグ
自動検出機能～不具合は現行犯で逮捕せよ！～【第一章】どんなバグが検出できるのか？

が当たり前になっています。そんな大規模ソフトウェアの開発で最も困ってしまうのは、「単体テストでは問題無く動作していたが、結合テストで不具合が起きる」というシーンではないでしょうか。
開発対象のソフトウェアの本来機能の仕様やアルゴリズムに関する不具合であれば、仕様に従って論理的に追いかける事が有効
ですが、意図せず不当にメモリが書き換わっていたようなアドレス
バグの場合は、目の前で起きている不具合現象は分かるものの、その原因となるバグがどこに潜んでいるのかを探すのが大掛かりになってしまいます。
·

SOLID 開発プラットフォームでは、不具合を作り込まない仕組
み、不具合をスマートに検出するための様々な仕組みを持っていに可能ですか？
·

全てのソースコードを開発者で共有できますか？

·

ソフトウェアの改訂によって、不具合の発生パターンが変わるのが特徴です。これらは、デスクトップソフトウェア開発環境としってしまい、バグの追い込みが振り出しに戻る事はありませて実績のあるものを、SOLID が組込みソフトウェア開発環境として初めて利用できるようにしたものです。

んか？
·法チェック機能（コンパイラのバックグラウンド実行により文法エラーを指摘）が有効です。また SOLID ではプログラムの流れを論理的に解析して不具合を検出できる静的解析機能も標準で備えており、簡単な操作だけで利用可能です。

結合テストを実施するためのハードウェア環境を、バグ解析のために長期間使用できますか？

不具合を作り込まないようにするには、SOLID-IDE が持っている
インテリセンス機能（コーディング支援）や、コンパイラの自動文

開発関係者が皆で集まり、合同デバッグする事は現実的·製品リリースまでに十分な期間はありますか？

不具合が出ている実機にデバッガを接続し、不具合現象が起きているソースプログラムを見ながら怪しい箇所に片っ端からブレー
クポイントを張り、break > step in > step out > step over を繰り返しているうちに、不具合の出方が変わってしまう、という辛

机上検証の後、実際にプログラムを動作させてはじめて現れるい「モグラ叩き」を延々と続けた経験をされた方もいらっしゃることと不具合の中で、ソフトウェア開発者が意図せず巻き込まれてしまでしょう。

う最も多いものがアドレスバグと称される「間違ったアドレスのメモリへのリード／ライト操作でデータを壊してしまう」ケースです。
SOLID にはこのアドレスバグを自動的に見つけるための実行時バグ検出機能を持っており、うっかりミスなどを効率よく検出しソフト
ウェアの品質向上に大変有効です。

また、アドレスバグとなった動作が実行されたあと、その影響が不具合となって表面化するまで大量のコードが走ってしまうので、実行履歴（トレース）を延々と追いかけなければいけない事もめずらしくはありません。しかもトレース情報をバッファするメモリ容量が有限なので、問題の原因となった実行箇所は既にその後の履

本書では、SOLID の実行時バグ検出機能であるアドレスバグの歴に上書きされてしまい、結局肝心な問題箇所が判らない事も自動検出を詳しく解説していきます。

あります。

第一章は、「どんなバグが検出できるのか？」についてご紹介しま

意図せずにうっかり作り込んでしまったアドレスバグは、作り込んです。第二章は、アドレスバグ自動検出の仕組みについて、第三しまった側が「見つけてもらうのを待つ」しかないのでしょうか？

章ではアドレスバグ検出機能の有効な使い方について、ご紹介します。

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 1

SOLID が自動検出できるアドレスバ
グの例
SOLID のアドレスバグの自動検出機能は、従来のデバッグ手法のような、バグのありそうなところに当たりをつけてブレークポイントを張って、トレース履歴を解析したり、コツコツと step 実行をしながらバグを追い込んでいくという手法ではありません。SOLID 環
境下でビルド～デバッグを行う一連の開発作業の中で、SOLID
がバグ検出のためのランタイムを生成し、それを実行するだけで自図 1-1 スタックオーバーフロー検出時の動検出機能を簡単に利用できるのが大きな特徴です。
また SOLID がアドレスバグを検出するのは、不当アクセスが発生した瞬間です。たとえそのバグが他のプログラムに何の影響を与えていなかったとしてもバグが検出できるため、単体テストの段階でも効果的に利用できます。

デバッガ画面表示

不当アクセス
ソプログラムのコード領域へ不当書き込みが起きると、本来動作するはずのプログラムコードが変わってしまうため「プログラムが暴以下に SOLID が自動検出できるアドレスバグの例をご紹介しま走」してしまいます。不具合現象が発生したとき、それが暴走にす。

よるものかどうかを判断することは容易ではありませんし、暴走しスタックオーバーフローているためにソフトウェアの流れを追う事すら難しいというのが実態です。

SOLID では、アドレスバグの代表的なものである、スタックオーバ
ーフローの自動検出が可能です。スタックオーバーフローは異常な
多重割り込みや、内部変数等のスタック情報の増加が原因で、設計時の想定以上のスタックを消費してしまい、スタックメモリの上限を突き抜けて他の領域にスタックを積んで（データを書き込んで）しまうという、組込みではよく目にするバグです。
SOLID では、ビルド時にツールチェーンで指定されたスタックメモリのアドレス範囲をツール側が把握しているので、デバッガを接続しまた不当書き込みによりコード領域を破壊してしまうような不具合は、ソフトウェアの規模が大きくなるにつれて、「他人の開発しているモジュールのコードを破壊する」という、自分では気づきにく
いやっかいなバグです。
そこで SOLID では、プロセッサのアクセス例外検出機能を利用して不当アクセスを検出できるようにしました。以下がその動作概要です。

た状態でプログラムが動作中にスタックオーバーフローが発生する

まず作成されたプログラムは、ビルド時に設定したプログラムのセクと、それを直ちに検出します。

ション情報に従い、ロードモジュールを生成するときに、

スタックオーバーフローが発生した場合は、図 1-1①のように、”Data Abort Exception caused by stack overflow”.text、.rodata、.data、.bssという属性の異なるセクションに分けられます（図 1-2）。

とデバッグ例外ウインドウに表示し、プログラムの続行を中断（ブレーク）します。またその時に RTOS ビューワー（図 1-1②）ではタスクに割り当てられたスタックの消費量をビジュアルに表示するので、どのタスクがスタックオーバーフローの要因になったのかを容易に知ることができます。
スタックオーバーフローはソースプログラムの静的解析により検出する事は困難なので、このような自動検出機能は大変有効で

図 1-2. ビルド時に設定したセクション情報に従い、SOLID が MMU のメモリ属性を設定す。しかも SOLID では特別な設定や、実行時間のオーバーヘッ
ド無しでスタックオーバーフローが検出できるというところも大きな利点といってよいでしょう。

各セクションは.text は実行コードなので、「ライト不可」、「実行可能」.rodata は read only データだから、「ライト不可」、「実行不可」

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 2

.data や .bss は、読み書き可能データだから、「ライト可」、

配列オーバーランとしては、上記の他にも memcpy()のようなメモ「実行不可」

リブロック操作命令に対してもバグがあれば自動検出が可能でという属性を持っており、セクションの属性に従い SOLID がMMU の設定を行います。

す。
この例で示した配列オーバーランは、SOLID のアドレスサニタイザ

MMU によりライト不可と設定されたコード領域へのライト動作が発生した場合には、メモリが書き換えられる前にプロセッサがアドレス例外を起こすので、SOLID デバッガと連動してバグ発生を検出しプログラムがブレークします。
実行不可領域でのプログラム実行も同様に検出します。

という専用の実行時バグ検出の仕組みを用いているので、ユーザーが意識的にブレークポイントを設定したり、検出対象の変数を指定する必要は全くありません。SOLID のビルド構成を「アドレスサニタイザモード」に指定するだけの簡単な操作でアドレスサニタ
イザが使用でき、バグを探し出す時間を大幅に短縮可能です。
ただし、アドレスサニタイザモードを使用する場合、バグ検出のた

また、セクションの存在しないアドレス領域には物理メモリを割りめのランタイムをユーザーコード中に埋め込んで動作させるため、当てないように SOLID が MMU を設定するので、リード・ライト

実行時間および使用メモリ（プログラムおよびワーク RAM）にオ

や命令フェッチ動作のいずれでもプロセッサ例外が発生し、上記

ーバーヘッドが発生します。

同様にバグを自動検出します。

このアドレスサニタイザの動作の詳しい仕組みについては、第二章で解説します。

配列オーバーラン配列として確保したメモリ領域に、配列サイズを超えてアクセスしようとした場合、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

関係のないネットワーク処理部の配列オーバーによる表示処理③）でバグの箇所を分かりやすく表示します。

部のワークメモリ破壊だった、という事もあり得ます。
SOLID ではバグ動作が起きた瞬間に、他のプログラム動作に何の影響が起きていなくても、アドレスバグを自動検出しますので、
アドレスバグを現行犯で逮捕できるところが、従来のモグラたたきでバグを追い詰めるデバッグ方法と大きく異なる点です。

自信をもって単体モジュールをリリースできる
アドレスバグのように、「うっかり」作り込んでしまいがちな不具合
を、単体レベルで自動的にあぶりだし事前につぶしておくことでソフトウェアの品質は大きく向上します。開発全体のスケジュールの
図 1-3.配列オーバーランを自動検出した際のデバッガ表示

中で、単体モジュールの検証という比較的初期段階でアドレスバ

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 3

グがつぶせるのと、結合テストが進んで様々なバージョンのコンフィ
グレーションのうち特定の組み合わせで時々発生する不具合症【第二章】アドレスバグ自動検出の仕組み

状をデバッグするのでは、デバッグコストも大きく異なります。また
悪いことに、時期的にも開発終盤でデバッグにかけられる残り時

第二章では、アドレスバグ自動検出の仕組みについてご紹介し間が少ない、ということもしばしばです。

ます。

特に開発規模が大きくなり、多拠点で分散開発をするような場

SOLID では、合は、不具合再現をするだけでも大きな労力を要するものです。委託先協力企業など、社外とのやりとりや段取りだけでも多大な時間を取られてしまうのが現実ではないでしょうか。
SOLID の実行時アドレスバグ自動検出機能を利用し、自信をもって単体モジュールをリリースできれば何よりです。

新しい開発スタイル、SOLID でスマートなデバッグ

Arm® Cortex®-A プロセッサのアクセス例外検出機能
Clang コンパイラのアドレスサニタイザ機能の２つを利用し、更に「SOLID ツールチェーン」、「MMU 設定」と「デバッガ」をシームレスに連携させることで、実行時アドレスバグ
自動検出機能を実現しています。本稿では、この 2 つの仕組みについて、少し詳しく解説をしていきます。アドレスバグ検出の仕組みを知ることで、ユーザーの皆様には SOLID を使ったデバッグ体験を！

に対して、「こういうバグはツールに任せれば自動検出できる」といSOLID は、既存の組込み系開発環境に先駆けて、これらのバ

う安心や信頼を実感していただけるのではないかと思います。

グ自動検出機能を利用できるようにした初の開発プラットフォー
ムです。テスト用入力パターンをわざわざ作成することなく、簡単な手順でバグ自動検出機能が使えるため、誰もがスマートにデバッグ作業を進める事ができます。

SOLID には２種類の実行時アドレ
スバグ自動検出機能がある

実行時アドレスバグ自動検出機能を使って開発効率をアップ
し、皆さんのソフトウェア開発パワーをよりクリエイティブな作業に集中していただきたいと思います。

Cortex-A プロセッサのアクセス例外
Cortex-A プロセッサでは MMU の設定により、ページサイズ（4KB）単位でメモリのアクセス権が設定できます。
「アクセス不可」、「ライト不可」、「実行不可」といった属性を設定した領域に対して、禁止された動作が実行された場合は、プロセッサがアクセス例外を起こします。SOLID デバッガを接続中にこの例外が発生した場合は、デバッガが例外を認識し、アドレスバグが発生したことを GUI 上に表示します。

Clang コンパイラを利用したアドレスサニタイザ
SOLID のもうひとつのアドレスバグ自動検出機能がアドレスサニタ
イザです。アドレスサニタイザは Google 社の研究チームが
LLVM コンパイラ基盤を利用して開発し、Apple 社の統合開発
環境 XCode に採用されて普及した実行時バグ検出機能です。コンパイラによる自動コード挿入（instrumentation）で不正なメモリアクセスを検出します。

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 4

アクセス例外検出の仕組み
MMU のメモリタイプ属性管理機能を活用する

するためのランタイムを生成し、そのランタイムを初期化処理の一部として実行します。このためユーザーは、自身のプログラムの中で煩雑な MMU の設定が不要になります。
また、論理<->物理アドレスの対応や、メモリセクション属性は、Cortex-A は MMU（メモリ管理ユニット）と TLB（トランスレー

SOLID のメモリマップデザイナで、分かりやすく参照、簡単に変更

ション・ルックアサイド・バッファ）を用いて、仮想アドレスを物理アができます（図 2-1）。メモリマップデザイナ上で行った変更は、ドレスに変換します。

MMU の設定内容にも反映されます。

Cortex-A の MMU では、4KB、64KB、1MB、16MB をサポー

なおプログラムのリリース時には、MMU 設定内容は SOLID コア

トするページテーブル エントリを有し、各エントリには、仮想アドレ

サービス（ターゲットの資源管理などを行うソフトウェア）の一部

ス、ページサイズ、物理アドレスとメモリタイプ属性が格納されまとして提供されます。

す。
このメモリタイプ属性には、次のようなものがあります。
⚫

アクセス不可⚫

リード可／ライト可⚫

リード可／ライト不可

これに加えて、実行禁止属性も設定できますので、不当メモリア
クセスを検出するには MMU を活用することが有効です。

図 2-1. SOLID メモリマップデザイナで、メモリ属性やしかし、Cortex-A プロセッサを使用する場合、MMU の設定が論理＜－＞物理アドレス対応を参照・変更

比較的複雑であることに加え、設定を間違えてしまうとそもそもプこのようにセクションの種別に合わせたメモリセクション属性が設定

ログラムのロードが出来なかったり、すぐに例外が発生してプログラされるため、プログラム実行中に不当なアクセス（ライト不可領

ムが起動しないなど、プログラムを動かすまでに苦労が多いのが域へのライトアクセスなど）があればただちにプロセッサ例外が発実態です。

生します。プロセッサ例外が発生した場合、SOLID デバッガでは

MMU の活用が有効と分かっていても、難しくて使えない、面倒

例外の種類を判定し、それをデバッガ画面上に表示します（第で使わない、そんな障壁を解消するため、SOLID では誰でも簡一章 図 1-3 でご紹介）。

単に MMU を使えるようメモリタイプ属性の自動設定機能を設

隙間を空けて論理アドレスにメモリを配置する

けています。

SOLID による MMU の自動設定の流れ

SOLID には論理アドレス空間に自動的にセクションデータを配置する機能があります。その際、セクションとセクションの間に隙間をまずビルド時、ロードモジュールを生成する際にはリンカスクリプト

空け、その隙間には物理アドレスを割り当てないことで、プログラで指示された内容に従い、以下の様なメモリセクション属性や、ムの暴走（図 2-2）やスタックメモリの突き抜け（図 2-3）など

論理<->物理変換などのテーブルが生成されます。

を、プロセッサのアクセス例外として検出できるようにしています。

.text（コード領域）.rodata（ライト不可のデータ、定数など）.data（リード／ライト可、実行不可）.bss（リード／ライト可、実行不可）
SOLID で対象ハードウェア（SoC やボードなど）を選択した時点で自動的にデフォルトのリンカスクリプトが選択されますので、ユーザーは特にリンカスクリプトの内容を意識する必要はありません。

図 2-2. プログラム暴走時は、コード領域境界でバグを自動検出

次にプログラムに実行時は、ビルド時に作られた前述のテーブル
情報をもとに SOLID が MMU の TLB やページテーブルを設定

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 5

アドレスサニタイザの仕組み
何を監視しているのか?
アドレスサニタイザの機能をシンプルに表現すると次の様になります。
メモリアクセス命令を実行する都度、アクセス対象が妥当かど
図 2-3. スタック突き抜け時は、スタックメモリ領域境界でバグを検出うかチェックする機構。
図 2-5 の例でその基本的な仕組みを説明します。

Cortex-A MMU のメモリエントリサイズは、4KB、64KB、1MB、プログラムをアドレスサニタイザモード(SOLID のコンフグレーション

16MB という単位で管理されます。もしプログラムで指定したスタ

では、Debug_Tasan モード)でビルドすると、メモリへのライト命令

ックメモリがこの単位と異なる場合は、SOLID はスタックの上限（ここでは buf[i]=i;）の直前にメモリチェック機能をもつランタイ（スタックを積む方向）にアドレス境界を合わせて配置しますム（以下チェックルーチンと呼びます）を呼び出すコードが自動（図 2-4）。というのも、スタックメモリに関わるバグの殆どが、スタ的に挿入されます。プログラム実行時には、メモリにライト動作がックの積み過ぎ（想定を超えた多重割り込みなど）が原因だか実行される直前に、毎回ライト対象のメモリが妥当かどうかをチェらです。

ックするプログラムが呼び出され、妥当性が確認されない場合には、プログラムの実行を中断し、デバッガに対して不当アクセスが発生したことを通知します。
（このプログラムは、第一章の解説でも登場した配列オーバーランの例です）

図 2-4 スタック上限をメモリエントリ境界に合わせて配置する
なお、論理空間上は隙間をあけてメモリを配置しますが、物理空間においては極力隙間を空けずにメモリを配置することでメモリを効率的に利用します。また SOLID がターゲットとしている
RTOS ベースのシステムにおいては１つの論理空間に全てのメモ

図 2-5 メモリチェックルーチンを呼び出すコードが自動的に挿入される

リを配置することで、メモリスワッピングなどによるリアルタイム性へ

アドレスバグ発生の可能性がある箇所を、コンパイの影響を受けないようにしています。

ラが厳選してチェックルーチンをコール

このアクセス例外によるバグ検出機能においては、実行プログラ

ユーザーはチェックルーチンをコールするコード挿入箇所をわざわざムサイズおよび実行時間に対するオーバーヘッドは発生しませ指定する必要はありません。

ん。
というのは、SOLID ツールチェーンに採用している Clang コンパイ
ラにはアドレスサニタイザモードにおいて、コンパイルの際にメモリア
クセス命令があるとその直前に予め指定されたチェックルーチンをコールするコード挿入する、という機能を持っており、SOLID がその機能を利用しているためです。
このアドレスサニタイザ機能を使う場合、チェックルーチンの実行
時間およびコードサイズのオーバーヘッドを最小限に抑えるため、プログラム中の全てのメモリアクセス命令に対してチェックルーチンを実行するわけではありません。Clang コンパイラがプログラム

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 6

を解析し、アクセス対象のメモリが論理的に問題ないアドレス

図 2-7 において、buf[i]の i=10 になったところで判定テーブルのにあると判定した場合は、チェックルーチンのコールは行いませ

内容が 0 となるため、チェックルーチンがこれを不正アクセスと判

ん。

定します。

上記図 2-5.の例のように、変数 i により buf[i]のアドレスが可変となるような、アクセス対象のメモリアドレスが確定しない場合にのみ、チェックルーチンをコールします。逆に、 i についてはメモリアクセスが発生する可能性があるものの、問題のないアドレスに配置されていることをコンパイラが知っているので、i のアクセス直前にはチェックルーチンをコールするコードを挿入せずにプログラムを実行します。

チェックルーチンがやっていること

図 2-7 有効無効アドレス判定テーブルを利用して、
不正アクセスを判定する

Clang コンパイラがアドレスサニタイザモードで実行するチェックルーチンは、SOLID が専用に用意したデバッグ専用のランタイムで少々細かい説明となりますが、この有効無効アドレス判定テーブ

あり、次のような動作をしています。

ルは、ターゲットメモリの中の “SOLID-RAM”という領域内に確

まず、アドレスサニタイザモードでビルドすると、論理空間上に変保されます。

数を配置する際にその前後に「ガード領域」を挿入します（図アドレスサニタイザモードでのバグ検出機能の仕組2-6）。ガード領域には物理アドレスが割り当てられていても構いみ（まとめ）

ませんが、プログラムの動作においてはアクセス無効と定義されます。

アドレスサニタイザによる実行時アドレスバグ自動検出の仕組みをまとめると、以下のようになります。
1.

コンパイラがプログラムを解析して不正アクセスが発生する
可能性のある個所にチェックルーチンを呼び出すコードを埋め込む

2.

コンパイラがガード領域を挟んで変数を配置

3.

実行時、関数の先頭で有効・無効アドレス判定テーブルを設定

4.

メモリアクセス命令が実行されると、SOLID が用意したラン
タイム上で動作するチェックルーチンがメモリアクセスの都度判定テーブルでメモリアドレスの有効・無効をチェック

図 2-6. 変数の間にガード領域を挿入
次にプログラムを実行すると、アドレスサニタイザの監視対象関数の先頭で、アドレスサニタイザ専用のランタイムが論理空間のアドレス 1 バイトに対して 1 ビットの有効無効ビットを持った、アドレス5.

アクセス対象が有効なメモリであれば、そのままプログラム
実行を継続

6.

無効アドレスへのアクセスを検出したらデバッガが IDE 経由
でユーザーに通知

判定テーブルを設定します。対応するアドレスが無効であれば”

このように、コンパイラ、デバッガ、IDE と SOLID 専用のランタイム0”、有効であれば”1”という値を持ったテーブルです（図 2-が密接に連携してはじめて実現できるアドレスバグ自動検出機

7）。

能を、SOLID ではアドレスサニタイザモードでビルド＆実行するだ

プログラムの進行に従いチェックルーチンが実行されると、アクセス

けで誰でも簡単に利用できるようになっています。

しようとしているアドレスの有効・無効をアドレス判定テーブルを参

このとき、変数の配置や、チェックルーチンの呼出しコード挿入も照して判定します。判定結果が有効であれば、チェックルーチン

全て SOLID が自動的に行うため、ユーザーがアドレスバグの発は何もせずに、続くメモリアクセス命令を実行します。一方、判定

生しそうな箇所を意識する必要はありません。

結果が無効の場合は、アクセス違反を検出し、デバッガに通知するためブレークを発生させます。

なお、アドレスサニタイザモードでは、変数間のガード領域、有効無効アドレステーブル、チェックルーチンやチェックルーチンを呼び出

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 7

すコードの挿入によりメモリ容量のオーバーヘッドがあります。ま【第三章】

た、チェックルーチン実行による実行速度低下が生じる点にも留意が必要です。

アドレスバグ自動検出の有効な使い方

第三章では、実行時アドレスバグ自動検出機能を有効に利用していただくためのヒントなどをご紹介していきます。

第一章、第二章では、実行時アドレスバグ検出機能がどのようなバグをみつけられるのか、どのような仕組みでバグを検出しているのかについて、ご紹介してきました。本章では、アドレスバグ自動検出機能を利用する際の留意事項や、有効な使い方、活用例などを中心にご紹介していきます。

アドレスバグ自動検出機能は万能ではない
検出しないケースもある
SOLID では、実行時アドレスバグ自動検出の仕組み上、次のようなケースでは意図しないメモリアクセスがあっても、それをバグとして検出しません。
スタック領域の目的外アクセス
スタックオーバーフローの自動検出は、予め設定されたスタックメモ
リを突き抜けて、メモリが存在しない領域にスタックを積もうとして例外となりバグを検出する仕組みですが、スタック操作以外の動作によりプログラムがスタック領域をアクセスした場合、そこが物理
メモリが割り付けられている論理アドレスであれば、この動作をバグとして検出しません。スタック領域のアクセスが不当なのか正当なのかはプログラムの仕様そのものに依存する問題であり、意図的に操作する事もあるので、メモリアクセス命令はそのまま実行されます（図 3-1）。

図 3-1. スタック領域の目的外アクセス

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 8

不連続な配列オーバーラン
配列アクセスにおいて配列の範囲をはみ出した場合には、アドレ
スサニタイザにより無効アドレスであると判定されてバグ検出ができます（検出の仕組みは第二章を参照してください）。
しかし、図 3-2 のように配列の要素を不連続に（ガード領域を飛び越えて）アクセスした場合、たまたまそのアドレスに他の変数が割り当てられていれば、配列としては正しくありませんが、アクセス対象が有効アドレスなのでアドレスサニタイザ機能が有効であってもこれをバグとして検出することが出来ません
図 3-3 アドレスサニタイザモード使用時のメモリ消費量オーバーヘッド
プログラムの内容によりオーバーヘッドは大きく変わりますが、アドレス有効無効テーブルは 1 バイトあたり 1 ビット必要なので、変数領域の 8 分の 1 がオーバーヘッドになります。また内部変数に関しては、ガード領域がスタック使用量増加になるので、スタック
オーバーフローが起きないよう、スタックサイズを 2 倍程度確保す
図 3-2. 不連続な配列オーバーラン

る必要があります。その他、変数間のガード領域やチェックルーチ
ンを呼ぶコードのオーバーヘッドもあるため、全体として、アドレスサ

もっとも、このようなプログラムを書いてしまった場合は、SOLID のニタイザを使わない時に比べて 1～3 割程度多くのメモリを消費

静的解析機能が論理的なバグとして指摘する可能性が高いのします。

で、実行前に不具合が判明することがほとんどでしょう。
仕様上ライト不可な変数は const 宣言しておくこと
仕様上ライト対象ではない変数に対して、意図しないプログラムが誤ってライト動作をした場合でも、アドレスサニタイザはこれをバ

また、変数アクセスの都度チェックルーチンが実行されるため、一般的なプログラムにおいてアドレスサニタイザモードで実行した場
合は、通常時に比べて実行時間が平均すると 2 倍程度遅くなります。

グとして検出することはありません。なぜなら、アドレスサニタイザでなお、MMU を利用したメモリ属性の違反検出（スタック突き抜

は対象アドレスの有効・無効のみを判断しておりリード・ライトとい

けや、const 宣言変数へのライト動作）においては、メモリ容量ったアクセス種別の判定はしていないからです。

や実行時間に対するオーバーヘッドは発生しません。

変数を確実にライト不可としたい場合は、const 宣言により定数に指定してください。const 宣言した変数はセクションのメモリ
属性がライト不可な .rodata に領域に割り当てられるため、その変数へのライト時にアクセス例外が発生し、確実にバグとして検実行時アドレスバグ自動検出機能の有効な使い方出可能です。

検出対象を指定することで、オーバーヘッドの影響

オーバーヘッドにも注意を少なく
アドレスサニタイザモードでデバッグをする場合、以下の理由により
図 3-3 に示すようなメモリ消費量のオーバーヘッドが発生します。
·

アドレス判定のためのチェックルーチンを呼ぶためのコード（図 3-3 ①）·

チェックルーチン（図 3-3 ②）·

変数の前後のガード領域（図 3-3 ③）·

アドレス有効無効テーブル（図 3-3 ④）

上記のように、アドレスサニタイザモードでの動作時にはメモリの消費量および実行時間に対するオーバーヘッドがあるため、制御対
象によっては正常に動作しない場合もあると思います。しかし、ア
ドレスサニタイザモードでは、「特定のプロジェクトだけ」「特定の関数だけ」を検出対象に指定できるという便利な使い方が可能です。

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 9

そのため、プロジェクト単位でアドレスサニタイザを利用したり、個別の関数単位でアドレスサニタイザモードを用いて予め検証し、結合時テストではアドレスサニタイザモードを全て外す、といった使い方でオーバーヘッドの影響を少なくすることが可能です。
一般的なテスト検証においては、バグがどこに影響を及ぼすかがわからないため、ソフトウェア全体を結合した状態で影響範囲の検証を行う必要があります。しかしアドレスサニタイザでは影響を及ぼされた側ではなく、影響を及ぼした側の不正アクセスを「現行犯逮捕」できる仕組みなので、部分的に分割してアドレスサニ
タイザを適用したデバッグでも、不正アクセスの検出に十分有効

図 3-4 メモリブロック操作命令では、です。

SOLID が独自にアドレスチェック回数を少なくする

チーム開発時のリビジョンアップ作業も安心

ここで使用した「特定の命令や関数をアドレスサニタイザの対象

ソフトウェアの規模が大きくなりチーム体制で開発する場合、担から除外する機能」は、Clang コンパイラが持っている機能です。

当モジュールを更新してリリースする前にアドレスサニタイザモード

この機能と、SOLID 独自の「API を活用してアドレスサニタイザのを有効にして実行テストをしておけば、他のモジュールへ影響をアドレスチェック回数を削減する仕組み」を活用することで、メモリ与えないことが確認できるため、安心してモジュールの更新＆リリ

ブロック操作におけるアドレスチェックルーチンの実行回数（実行ースが出来ます。

時間のオーバーヘッド）を大幅に削減することができます。

malloc、free 関数によるメモリの動的割り当てもアドレスサニタイザ機能の SOLID 流

監視

アレンジ

SOLID 独自の機能として、malloc、free 関数によるメモリの動的割り当ても監視しています。

memset()、memcpy()関数では効率よくメモリを

アドレスサニタイザモードでは、malloc 関数が実行された場合チェックするに、当該アドレス領域に対してアドレス有効・無効テーブルを「有効」にセットし、free 関数が実行されたら、その領域は「無効」に

アドレスサニタイザモードにおいては、メモリアクセス命令を実行すします。また、malloc、free 関数の先頭では、アドレス有効・無る度に対象のメモリが有効か無効かを判定するチェックルーチンを効テーブルのチェックをするルーチンを追加します。

実行しています。そのため、memset()や memcpy()といったメモ
リブロック操作関数では操作対象の全アドレスに対してメモリアクプログラムを実行中、free 関数実行の際に、既にその領域がセスの都度 有効無効チェックが実行され、実行時間のオーバー「無効」になっていた場合は、「二重解放」に当たるため、SOLID

ヘッドが大きくなってしまうという懸念があります（図 3-4 左）。

はこれを不正動作として検出し、プログラムをブレークしてデバッガ
を通してユーザーに通知します。

そこで SOLID では独自の機能で対処しています。まず、SOLID
で用意しているライブラリの memset()および memcpy()で行わ同様に、free 関数実施後に当該アドレス領域をアクセスした場

れるメモリアクセスは、アドレスサニタイザの対象から除外されてい合も、不正動作として検出します。

ます。

ブレークした箇所を分かりやすく表示

そのうえで、関数の先頭で一度だけ操作対象アドレスの全範囲

これまでご紹介してきたように、アドレスサニタイザモードを使ったデが有効か無効かをチェックし、一部でも無効アドレスであれば、アバッグではユーザーが作成したプログラムに対して、不正検出やデドレスバグとして検出を行うよう、SOLID 独自の API を用意してバッグのためのコード（ランタイム）が多数追加されて走っていま

オーバーヘッドを少なくしています。逆に全域が有効アドレスであす。

ればメモリブロック操作命令を実行します。（図 3-4 右）。

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 10つまり、アドレスバグを自動検出してプログラムがブレークした瞬間

このように、デバッグ担当者が意図的にブレークポイントを張るとの PC(プログラムカウンタ)は、ユーザーのコードとは別の不正検出いう操作は行わず、ソースコードも無い状態でしたが、即座に不やデバッグのためのコードの中にあることになります。

具合箇所が見つかり対策する事が出来ました。

この PC はデバッグ対象であるユーザー自身のコードの中ではな

なおこの例では、テスト用の機能を有効にしてビルドした場合に、いため、デバッガの画面ではブレークした PC の箇所ではなく、不通常時よりも多くのスタックメモリを消費する機能が動作するのが正の元となったユーザープログラムのソースコードの箇所を分かり直接的な原因でした。すなわちコードに本質的な問題があったわ

やすく表示する工夫をしています。またトレース履歴にはブレーク

けでなく、いわば設定ミスのようなものでした。

するまでに走ったコードのトレース情報が不正検出用のコードを含めて記録されていますが、不正が発生したユーザーコードの箇所が判るように表示をする、といった配慮もしています。

従来の RTOS での開発においては、このようなトラブルのときには、スタックを破壊してから暴走するなり不正な動作になってしまうので、原因を一瞬で突き止める、ということはなかなかできませんでした。過去の経験で「スタックサイズが原因かも？」と思うこと

利用者の体験からができれば早期解決は可能ですが、そうでない場合には、どこまで正しく動作したか、ということをブレークポイント設定したり、また最後になりますが、SOLID の実行時アドレスバグ自動検出機能

ログを仕込んだりするところからデバッグを始めなければなりませを使って便利にデバッグができた体験談を紹介いたします。

ん。設定ミスであっても通常のデバッグ並みに多くの時間を消費

ソースコード無し、バイナリで入手したライブラリの実装デバッグすることもあるのです。しかし SOLID のスタックオーバーフロー自動検出機能では、このようにスタックが足りなくなった状況を即座にユーザーに通知するので、無駄な時間を消費することがありませある SoC を搭載したボードに、外部から提供された画像処理ラん。

イブラリのポーティング作業をすることになりました。画像処理ライ

最後にブラリはバイナリだけの提供で、ソースコード無しという条件でした。

従来のデバッグ手法では、正当なメモリの利用者が実害を受けてから不具合現象がわかり、そこから真犯人を探す旅が始まるわ

SOLID 環境でライブラリのポーティング後にデバッガを接続してプけですが、SOLID の実行時アドレスバグ自動検出機能を活用

ログラムを実行させたところ、プログラムがブレークし、SOLID IDEすることで、不当アクセスが起きた瞬間に現行犯で犯人を逮捕

がスタックオーバーフローを表示しました（図 3-5 オーバーフロー

できるのです。本書を通して、皆様にもその違いの大きさがお分したタスクのスタック使用量が赤で表示されるため、すぐに気付くこ

かりいただけたことと思います。

とができました)（終）

図 3-5 スタックオーバーフロー発生時のデバッガ画面
RTOS ビューアでスタックオーバーフローを起こしたタスクを確認し、そのタスクのスタックサイズを 2 倍に設定して再試行してみたところ（ソースコードが無くてもスタックサイズは変更可能です）今度はエラーの発生はなく、無事にポーティング作業が終了しました。

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 11この記事はこちらからもお読みいただけます。

©2018 京都マイクロコンピュータ株式会社※ 記載の社名・製品名は各社の登録商標または商標です。記載内容は予告なしに変更する場合があります。

ソフトウェア開発プラットフォーム SOLID 技術解説書 page 12
2018.6(第 1 版)