C言語のセキュアなコーディング力を身につけるため、再履修するシリーズ。
DCL17-C. volatile 修飾された変数が間違ってコンパイルされることに注意
https://www.jpcert.or.jp/sc-rules/c-dcl17-c.html
うんうんvolatileは大切よね、くらいの気持ちで読み始めたのだが、思っていたのと全然違った。
しかし、"Volatiles are miscompiled, and what to do about it" [Eide and Regehr] が示したように、彼らがテストしたコンパイラのすべてが、
volatile
アクセスという点に関して何パーセントかの間違ったコードを生成した。
コンパイラのバグの話か!
私が新卒で入社した頃だが、組み込みのコンパイラでdoubleだったかfloatだったか、どっちか忘れたけど最適化とあわせると正しくない結果になるというコンパイラが使われていてね。
ふっとそんな昔のことを思い出してしまった。
記事では、IA32向けのGCC4.3.0+サイズ最適化オプションでの事例を紹介している。
そう、だいたいこういうのは最適化とセットで起きるのよね。
だから最適化禁止にしているプロジェクトもしばしばだ。
ここでは、引数をそのまま返す関数を用意して、変数参照ではなく関数呼び出しさせることでバグを回避する方法を紹介している。
が・・・バグがあると分かっていればやるだろうけど、まず初っぱなからこういう書き方はしないよなぁ。。。
コンパイラに頼れないので、情報だよりか、実経験だよりになる。
情報は、コンパイラのバグを知るしかないだろう。
そうなると、最新版ではなく、少し枯れたコンパイラを使う方が無難かもしれない。が、最新版だからこそバグが治っているということもあり、くぅ。。。。
実体験に頼る方も考えておいた方が良かろう。
しかし、コンパイラは常に進化し続けているため、クリティカルなコードについては、実配備を想定してコンパイルし、その結果のオブジェクトコードが正しいふるまいをするかどうかを確認すべきである。
問題はどうやって「正しいふるまいをするかどうかを確認」するかなのだが、アセンブラなんかいちいち確認したくない。
ほしいのは、このコードをコンパイルして、実行結果がこうなればOK、みたいなやつなのだが、CPUに依存してしまうとなると簡単ではないな。
実行して、volatile効果がすぐにわかるコードというと、私には並列動作くらいしか思いつかない。
スレッドでも割込みでも良いので、並列して動かして、片方はループでvolatile変数をチェック、もう片方はそのコンテキスト以外でvolatile変数を変更、というやつだ。
スレッドならまだしも、割り込みハンドラなんかを使うとなると、環境依存になってしまって難しいな。
じゃあ関数化するかというと、これも逃れられたのが確認できたというだけで、コンパイラのバグである以上、関数化すれば必ず大丈夫とは言いきれないだろう。
あれ、そうなると、volatile以外は大丈夫なのか? 関数の呼び出し順序なんかもある程度変更することが許容されているようなことが本に書かれていた気がするので、違う部分の最適化バグが出てくることもあろう。
とか考え出すときりが無い。
結局のところ、信頼せずに検証するしかないのかね。
0 件のコメント:
コメントを投稿
コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。
注: コメントを投稿できるのは、このブログのメンバーだけです。