メインコンテンツ

C Function ブロック内のカスタム コードに対する Polyspace 解析の実行

Simulink® から C Function (Simulink) ブロック内のカスタム C コードに対する Polyspace® 解析を実行できます。Polyspace では、Simulink モデルで指定された設計範囲指定、性質、入力の数などのモデル固有の情報を保持しながら、カスタム C コードのエラーやバグをチェックできます。

前提条件

Simulink から Polyspace を実行する前に、Polyspace インストールと MATLAB® インストールをリンクしなければなりません。MATLAB や Simulink との Polyspace の統合を参照してください。

この例で使用されるモデルを開くには、MATLAB コマンド ウィンドウで以下を実行します。

openExample('polyspace_code_prover/CScriptDemoExample')
open_system('psdemo_model_link_sl_cscript');

C Function ブロック内のカスタム コードに対する Polyspace 解析を実行するためのモデルを開く

このモデルでは、Command Strategy サブシステムの内部に controller という名前の C Function ブロックが含まれています。

Command Strategy ブロックは、カスタム C コードを使用してルックアップ テーブルを実装し、2 つの入力 xy に基づいて値 result を出力します。

Polyspace 解析の実行

Polyspace エディターからの Simulink 解析の実行

[アプリ] タブをクリックし、[Polyspace コード検証] を選択して [Polyspace] タブを開きます。

  1. [Polyspace] タブの [モード] セクションで [Bug Finder] または [Code Prover] を選択します。[Code Prover] の解析ではランタイム エラーが検出される一方、[Bug Finder] の解析ではコーディングの欠陥とコーディング ルール違反が検出されます。

  2. C Function ブロック内のカスタム C コードに対して Polyspace 解析を実行するには、[解析] セクションのドロップダウン リストから [モデルで使用されるカスタム コード] を選択します。

    A section of the Polyspace tab on the Simulink toolstrip. In this section, you can specify which code to analyze, and then run analysis.

  3. Polyspace 解析を開始するには、[解析の実行] ボタンをクリックします。MATLAB コマンド ウィンドウに解析の進行状況が表示されます。

  4. 解析後、Polyspace ユーザー インターフェイスで結果が開きます。[設定][検証後に結果を自動的に開く] の選択を解除して、解析後に結果が自動的に開かないようにすることもできます。解析終了後に結果を開くには、[解析結果] ボタンをクリックします。

  5. Polyspace 解析のフィルター処理されていない結果を表示するには、[結果のリスト] ペインの [表示中] ドロップダウン リストから [アクティブなフィルターをクリア] をクリックします。Code Prover 解析を実行すると、コントローラー サブシステムのフィルター処理されていない結果に 2 つのレッド チェックと 1 つのオレンジ チェックが含まれます。

  6. 結果をファミリ別に整理するには、square drop down menu をクリックして [ファミリ] を選択します。

    Results list organized by family of results. The top level shows result types such as Run-time Check, Global Variable, and so on. Within run-time checks, the results are organized by check color.

Bug Finder 解析と Code Prover 解析を切り替えるには、Polyspace ユーザー インターフェイスから Simulink エディターに戻ります。[モード] セクションで [Bug Finder][Code Prover] を切り替えて、解析を再度実行します。

MATLAB からの Polyspace 解析の実行

MATLAB エディターまたはコマンド ウィンドウで次のコードを使用して、このモデルのカスタム コードに対する Polyspace Code Prover™ 解析を実行できます。

% Load the model 'psdemo_model_link_sl_cscript'
load_system('psdemo_model_link_sl_cscript');
% Create a 'pslinkoptions' object
mlopts = pslinkoptions('psdemo_model_link_sl_cscript'); 
% Specify whether to run 'CodeProver' or 'BugFinder' Analysis
mlopts.VerificationMode = 'CodeProver';
% Specify custom code as analysis target and run the analysis
pslinkrun('-slcc','psdemo_model_link_sl_cscript',mlopts);

C コード内の問題の特定

カスタム C コード内の問題を特定するには、Polyspace ユーザー インターフェイスの [結果の詳細] ペインと [ソース] ペインの情報を使用します。これらのペインが表示されない場合、[ウィンドウ][ビューの表示/非表示] に移動して、表示されないペインを選択します。ペインの詳細については、Polyspace デスクトップ ユーザー インターフェイスの結果の詳細 および Polyspace デスクトップ ユーザー インターフェイスのソース コード を参照してください。

[ソース] ペインでの C Function ブロック入力および出力の特定

Polyspace では、C Function ブロック内のコードがカスタム コード ラッパーでラップされます。C Function ブロックの入力と出力はグローバル変数として宣言されます。カスタム C コードは関数と呼ばれます。

/* Variables corresponding to inputs ..*/
// global In... 
/* Variables corresponding to outputs*/
// global Out...
/* Wrapper functions for code in block  */
// void ...(void){
    //...
}

  • 入力に対応するグローバル変数の名前は In で始まります (In1_psdemo_model_link_sl_cscript_98_Command_strategy など)。

  • 出力に対応するグローバル変数の名前は Out で始まります (Out1_psdemo_model_link_sl_cscript_98_Command_strategy など)。

  • void-void 関数には、入力変数と出力変数がグローバル変数に置き換えられたカスタム C コードが含まれています。複数の C Function ブロックがある場合、各ブロック内のコードは別個の関数でラップされます。

グローバル変数は、C Function ブロックの入力と出力のデータ範囲、データ型、サイズを含むプロパティを反映しています。複数の入力がある場合、グローバル変数の順序は C Function ブロックで定義されている入力の順序と同じです。次の表は、この例のブロックの入力変数と出力変数、およびそれらに対応する [ソース] ペイン内のグローバル変数を示しています。

[ソース] ペイン内のグローバル変数名スコープC Function ブロック内の変数名
In1_psdemo_model_link_sl_cscript_98_Command_strategy入力x
In2_psdemo_model_link_sl_cscript_98_Command_strategy入力y
Out1_psdemo_model_link_sl_cscript_98_Command_strategy出力result

[ソース] ペインでラップされたコードをレビューして、カスタム コードの問題を特定します。[ソース] ペインのツールヒントと [結果の詳細] ペインの情報を使用して、問題を修正します。このワークフローは、Code Prover 解析と Bug Finder 解析に適用されます。

不適切にデリファレンスされたポインター

レッド チェック [不適切にデリファレンスされたポインター] では、for ループ後のデリファレンス演算が強調表示されます。

tmp = *p + 5;
[結果の詳細] ペインには、ポインター *p が範囲外であることが示されます。このチェックの根本原因を見つけるには、無効なデリファレンスの原因となるポインターのライフサイクルを追跡します。

  1. ポインター *p は、そのライフサイクルの開始時に 100 個の要素を含む array の最初の要素を指しています。

  2. その後、p が 100 回インクリメントされ、*parray[100] という存在しない場所を指します。

  3. tmp = *p+5; のデリファレンス演算は無効となり、レッド チェックが生成されます。

範囲外の配列インデックス

レッド チェック [範囲外の配列インデックス] では、if 条件内の配列インデックス演算が強調表示されます。

 if (another_array[return_val - i + 9] != 0)
[結果の詳細] ペインには、another_array のサイズが 2 であるのに対して、インデックス値 return_val-i+9 の範囲が 2 ~ 18 であることが示されます。このチェックの根本原因を見つけるには、ツールヒントを使用して変数 return_vali の値を追跡します。[ソース] ペインで変数のインスタンスにカーソルを合わせると、ツールヒントが表示されます。

  1. i の値は 100 です。

  2. 優先条件 if ((return_val > 92) && (return_val < 110)) のため、return_val の値の範囲は 93 ~ 109 です。

  3. インデックス値 (return_val-i+9) は 2 ~ 18 の範囲として評価されます。

  4. インデックス値は配列 another_array の範囲外となり、レッド チェックが生成されます。

オーバーフロー

オレンジの [オーバーフロー] チェックでは、return_val への代入が強調表示されます。[結果の詳細] ペインには、このチェックが限定的な入力値に関連するものであることが示されます。このチェックの根本原因を見つけるには、ツールヒントを使用して変数のデータ型と対応する範囲を確認します。

  • 入力値 xy は、それぞれ以下のグローバル変数に対応しています。

    • In1_psdemo_model_link_sl_cscript_98_Command_strategy

    • In2_psdemo_model_link_sl_cscript_98_Command_strategy

  • 1 つ目の入力 x は、無制限の符号なし整数です。x は無制限であるため、符号なし整数の全範囲である 0 ~ 65535 の値を取ります。

  • 2 つ目の入力 y は、0 ~ 1023 の範囲の限定的な符号なし整数です。

  • x-y は、無制限の符号付き整数 return_val に代入されます。return_val は無制限であるため、-32768 ~ 32767 の全範囲の値を取ります。

  • x-y の範囲は 1023 ~ 65535 ですが、return_val の範囲は -32768 ~ 32767 です。

  • x-y の取りうる値の一部が return_val に収まらないため、オレンジ チェックが発生します。

Polyspace 解析結果の解釈の詳細については、Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈を参照してください。

特定された問題の修正

カスタム C コードまたはモデルを変更して、問題を修正します。Polyspace のチェックはいくつかの方法で修正できます。以下の例は、Polyspace のチェックを修正する一般的なワークフローを示しています。

不適切にデリファレンスされたポインター

このチェックには、いくつかの方法で対処できます。存在しないメモリ アドレスにアクセスしないように C コードを変更します。

  1. Simulink エディターに戻り、C Function ブロックをダブルクリックしてカスタム コードを開きます。

  2. array のインデックス演算子を使用して、有効な配列インデックスにアクセスします。array には 100 個の要素があるため、0 ~ 99 のインデックスにアクセスできます。この範囲を超えてインデックスにアクセスすると、Simulink でランタイム エラーが発生します。

    // access any index between 0 to 99
    tmp = array[50] + 5; 
    または、デリファレンス演算の前に p に有効なメモリ位置のアドレスを代入します。たとえば、*parray の 51 番目の要素を指すことができます。
    // After the for loop, point p to a valid memory location
    p = &(array[50]);
    // ...
    tmp = *p + 5;
    

範囲外の配列インデックス

このチェックには、いくつかの方法で対処できます。another_array[] のサイズがインデックス値 return_val-i+9 以上になるようにコードを変更します。

  1. Simulink エディターに戻り、C Function ブロックをダブルクリックしてカスタム コードを開きます。

  2. return_val の取り得る値についてインデックス値 return_val-i+90 または 1 として評価されるように、return_val に対する優先条件を変更します。

    if ((return_val > 91) && (return_val < 93))
    //...
    
    または、another_array をサイズ 19 で宣言します。
    int another_array[19];

オーバーフロー

このチェックにも、いくつかの方法で対処できます。代入演算の右側の範囲が左側の範囲以上になるように C コードまたはモデルを変更します。

  1. Simulink エディターに戻ります。

  2. モデルの入力変数 xy の差異が 16 ビット整数に収まるように、これらの変数を飽和させます。Saturation ブロックを使用して [オーバーフロー] を修正するワークフローについては、C Caller ブロックおよび Stateflow チャート内のカスタム コードに対する Polyspace 解析の実行を参照してください。

または、カスタム C コードで return_val のサイズを x-y に合わせて増やします。

  1. Simulink エディターに戻り、C Function ブロックをダブルクリックしてカスタム コードを開きます。

  2. return_val を 32 ビット整数として宣言します。

    int32_T return_val;

Polyspace の結果への対処の詳細については、Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処を参照してください。

参考

|

トピック