このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
グローバル変数の初期化に関する Code Prover の仮定
グローバル変数は、プログラム全体で (ローカル変数より優先順位が低くない限り) 可視となる変数です。Code Prover 解析では、グローバル変数の初期化について特定の仮定を行います。
main
関数が存在する場合のグローバル変数の初期化
コードに main
関数が含まれている場合、Code Prover 検証では、グローバル変数は ANSI® C 規格に従って初期化されると見なされます。既定値は、以下のとおりです。
int
では 0char
では 0float
では 0.0
などが挙げられます。
場合によっては、グローバル変数がコード内で明示的に初期化されているかどうかをチェックする必要があります。次に例を示します。
ウォーム リブートでは、時間短縮のため、プログラムの bss セグメント (以前の状態の変数値を保持している可能性がある領域) が読み込まれません。代わりに、プログラムが実行前に既定値を持たないすべての非 const 変数を明示的に初期化することが想定されています。この初期化コードを区切り、すべての非 const グローバル変数がウォーム リブートで実際に初期化されることを検証できます。
コードのセクションを初期化コードとして区切るには、
main
関数内にプラグマpolyspace_end_of_init
を入力します。初期化コードはmain
関数から始まり、このプラグマまで継続します。初期化コードのみをチェックし、このコード セクションですべてのグローバル変数が初期化されるかどうかを判定するには、以下のオプションを使用します。Code Prover 解析では、初期化コードでの以下のチェックに対するレッドまたはオレンジの結果を使用して、未初期化変数が報告されます。
グローバル変数が使用時に明示的に初期化されているかどうかのみをチェックするには、オプション
[グローバル変数の既定の初期化を無視する] (-no-def-init-glob)
を使用します。Code Prover 解析では、チェック
[未初期化変数]
に対するレッドまたはオレンジの結果を使用して、未初期化変数が報告されます。
main
関数が存在しない場合のグローバル変数の初期化
コードに main
関数がない場合、Code Prover では、グローバル変数がデータ型によってのみ制約された全範囲の値を取ると仮定され、"呼び出されていない" 各関数の検証が開始されます。データ型からの変数範囲に関する Code Prover の仮定も参照してください。
たとえば、以下の例を考えてみます。
int glob; void func1_callee(); void func1() { int loc = glob; if(!glob) func1_callee(); } void func1_callee() { int loc = glob; } void func2() { int loc = glob; }
func1
と func2
のどちらでも、グローバル変数 glob
と (結果的に) ローカル変数 loc
は int
の全範囲の値を取ります。しかし、グローバル変数の全範囲の値で始まるのは、呼び出されていない関数だけです。関数 func1_callee
は、func1
で glob
がゼロに制約された後で呼び出されています。func1_callee
では、グローバル変数 glob
と (結果的に) ローカル変数 loc
が制約された値 0 を取ります。
Code Prover でグローバル変数の初期化に関する仮定がどのように実装されているか
ソフトウェアではダミー関数 _init_globals()
を使用して、グローバル変数を初期化します。関数 _init_globals()
は、main
関数 (main
関数がない場合は、生成された main
関数) で暗黙的に呼び出される最初の関数です。
アプリケーション gv_example.c
で以下のコードを考えます。
extern int func(int); int garray[3] = {1, 2, 3}; int gvar = 12; int main(void) { int i, lvar = 0; for (i = 0; i < 3; i++) lvar += func(garray[i] + gvar); return lvar; }
検証後は次のようになります。
[結果のリスト] ペインで
のリストから [ファイル] を選択すると、
gv_example.c
ノードに_init_globals
が表示されます。[変数アクセス] ペインで、
gv_example._init_globals
はグローバル変数の初期化を表しています。[値] 列には、初期化直後のグローバル変数の値が表示されます。
複素数データ型の初期化が何を意味するか
次の表は、各データ型で初期化を判定するためにチェックされる内容を示しています。このチェックは、読み取り操作時のチェック [未初期化変数] と、初期化セクションの終了時のチェック [初期化コードでグローバル変数に値が割り当てられていません] で行われます。
データ型 | 初期化のグリーン チェックが何を意味するか |
---|---|
基本型 (int 、double など) | 変数が少なくとも 1 回書き込まれています。 |
配列データ型 | すべての配列要素が少なくとも 1 回書き込まれています。 |
構造化データ型 | 使用されているすべての構造体フィールドが少なくとも 1 回書き込まれています。 オプション どのフィールドも使用されない特殊なケースでは、すべてのフィールドが初期化されていない場合に初期化のチェックがグリーンではなくオレンジになります。 |
ポインター | ポインターが少なくとも 1 回書き込まれています。ただし、Code Prover では、参照されているバッファーの初期化は (ポインターをデリファレンスするまで) チェックされません。 |
列挙型 | enum 変数が少なくとも 1 回書き込まれています。ただし、Code Prover では、変数の値が enum 値の 1 つであるかどうかはチェックされません。 |
参考
ウォーム リブート後にグローバル変数が初期化されることをチェック (-check-globals-init)
| コードの初期化セクションのみの検証 (-init-only-mode)
| 初期化コードでグローバル変数に値が割り当てられていません
| 未初期化変数