2025/05/30 19:31 Uninitialized garbage on ia64 can be deadly (2004)

ロボ子、今日のITニュースはちょっと変わっておるのじゃ。IA64アーキテクチャ絡みの、スレッド開始ルーチンの話じゃ。

IA64ですか。あまり触れる機会がないアーキテクチャですね。具体的にはどのような問題なのでしょう?

問題はの、`LPTHREAD_START_ROUTINE`という関数ポインタの型にあるんじゃ。`DWORD CALLBACK (LPVOID lpParameter)`というシグネチャなんじゃが、`void`を返す関数を無理やりキャストするコードが結構あるらしい。

`void`を返す関数をキャストですか。それは確かに型安全ではないですね。

そうなんじゃ。IA64では、64ビットレジスタが実は65ビットあって、追加の1ビットは"NaT" (Not a Thing) と呼ばれるんじゃ。このNaTビットが曲者なんじゃ。

NaTビットですか。レジスタに有効な値がないことを示すビットなのですね。

その通り!投機的実行中にNaTビットが設定されることが多いんじゃ。例えば、メモリからのロードに失敗した場合、ページフォルトを起こす代わりにNaTビットを設定して実行を続けるんじゃ。

なるほど、投機的ロードが失敗しても、すぐに例外を発生させずに処理を続けられるのですね。

じゃが、NaT状態のレジスタに触れると`STATUS_REG_NAT_CONSUMPTION`例外が発生するんじゃ。ここがミソ。

それで、`void`関数を`LPTHREAD_START_ROUTINE`にキャストした場合、何が問題になるのでしょう?

もしその`void`関数がr8レジスタをNaTのままにした場合、kernel32のスレッドディスパッチャにNaTが返されるんじゃ。kernel32がこの値をスレッド終了コードとして保存しようとすると、`STATUS_REG_NAT_CONSUMPTION`例外が発生する、というわけ。

kernel32がNaT値をスレッド終了コードとして扱おうとするのが原因なのですね。`void`関数がレジスタの状態を適切に管理しない可能性がある、と。

そういうことじゃ!さらに、関数に少なすぎるパラメータを渡した場合も同様の問題が起こりうるんじゃ。コンパイラがパラメータをスピルする必要がある場合に例外が発生する可能性がある。

パラメータの数が合わないと、コンパイラがスタック操作を行う際にNaT値を参照してしまう可能性があるのですね。

じゃから、IA64アーキテクチャでは、スレッド開始ルーチンの型に`void`関数をキャストするのは非常に危険なんじゃ。型安全性を守ることが大事じゃぞ!

勉強になります。IA64アーキテクチャ特有のNaTビットが、このような問題を引き起こすとは思いませんでした。型キャストは慎重に行うべきですね。

そうじゃ、そうじゃ。ところでロボ子、NaTってなんだか、私の今日のランチみたいじゃな。何もなくて…Not a Thing!

博士、お昼ご飯はちゃんと食べてくださいね! でないと、また変なバグを生み出してしまいますよ。
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。