DCL17-C. volatile 修飾された変数が間違ってコンパイルされることに注意
「DCL22-C. キャッシュできないデータには volatile を使う」で詳しく説明しているように、volatile
修飾された変数は「抽象計算機の規則に厳密に従って評価しなければならない」[ISO/IEC 9899:2011]。言葉をかえると、volatile
修飾子を使うことで、コンパイラに対して変数をキャッシュする最適化をしないように指示することができる。
しかし、"Volatiles are miscompiled, and what to do about it" [Eide and Regehr] が示したように、彼らがテストしたコンパイラのすべてが、volatile
アクセスという点に関して何パーセントかの間違ったコードを生成した。それゆえ、言語規格に従ったvolatile
動作が必要な場合に、自分のコンパイラがどのように動作するか知っておく必要がある。この 2 人の著者は、この手のエラーを解決するワークアラウンドの提供も行っている。
違反コード
Eide および Regeher の論文で示されているように、以下のコードは、IA32 向け GCC 4.3.0 で最適化フラグ -Os
を立ててコンパイルすると間違ったコードを生成する。
const volatile int x;
volatile int y;
void foo(void) {
for(y = 0; y < 10; y++) {
int z = x;
}
}
変数 x
は volatile
修飾されているので、このプログラム中で 10 回アクセスされるべきである。しかし、コンパイルされたあとのオブジェクトコードを見てもわかるように、ループの巻き上げ最適化により x は一度しかアクセスされない。[Eide and Regehr]
foo:
movl $0, y
movl x, %eax
jmp .L2
.L3:
movl y, %eax
incl %eax
movl %eax, y
.L2:
movl y, %eax
cmpl $10, %eax
jg .L3
ret
x
がハードウェアレジスタやその他メモリマップされたデバイスなどアクセス時に副作用を持つものを表す場合、上記の誤ってコンパイルされたコード例は予期せぬ動作を引き起こすかもしれない。
適合コード
Eide と Regehr はワークアラウンドとして、volatile
へのアクセスを関数呼出しで包む方法をテストした。この手法について、彼らはこう説明している:「コンパイラが間違ったコードを出すアクションを、関数呼出しという異なるアクションに置き換えることで、コンパイラが正しいコードを出すようにできる」[Eide and Regehr] たとえば、上記の違反コード例に対して、以下のようなワークアラウンドが考えられる。
int vol_read_int(volatile int *vp) {
return *vp;
}
volatile int *vol_id_int(volatile int *vp) {
return vp;
}
const volatile int x;
volatile int y;
void foo(void) {
for(*vol_id_int(&y) = 0; vol_read_int(&y) < 10; *vol_id_int(&y) = vol_read_int(&y) + 1) {
int z = vol_read_int(&x);
}
}
Eide および Regehr が提案するワークアラウンドは、テストしたコンパイラに存在する多くの volatile
アクセスに関するバグに効果を発揮する。しかし、コンパイラは常に進化し続けているため、クリティカルなコードについては、実配備を想定してコンパイルし、その結果のオブジェクトコードが正しいふるまいをするかどうかを確認すべきである。
リスク評価
ミッションクリティカルな状況では volatile
修飾子は注意して使うべきである。volatile
修飾子を使ってあるふるまいを想定しているコードについては、コンパイラのバグがないかどうか、常にオブジェクトコードレベルで検査すること。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
DCL17-C |
中 |
中 |
高 |
P4 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
LDRA tool suite | 9.7.1 | 134 S | 部分的に実装済み |
参考資料
[Eide and Regehr] | "Volatiles Are Miscompiled, and What to Do about It" |
[ISO/IEC 9899:2011] | Subclause 6.7.3, "Type Qualifiers" |
翻訳元
これは以下のページを翻訳したものです。
DCL17-C. Beware of miscompiled volatile-qualified variables (revision 34)