閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

非同期のやり取りににローカル変数を使ってはいけません

下らない現象に長いことはまってしまった。とりあえず恥ずかしいことでもなんでも、後々のために溜め込んでおこうというのもこの日記の目的(?)のひとつなので(今作った)、メモしておこう。

事は至極簡単で、 PostMessage の引数に、ローカル変数のアドレスを渡してしまったというだけのことなのですが、簡単であるがゆえに歯がゆい。

説明すると、 PostMessage というのは WindowsAPI に用意されている関数で、指定したスレッドに対してメッセージを送るというもの。で、問題なのはこの関数が非同期であり、処理が完了する前に制御が戻ってきてしまうため、メッセージ送信先の関数が渡したアドレスを受け取って処理する前に、呼び出しもとの関数が終わってしまう可能性があるということです。つまり渡したアドレスの先にある変数の実体は解放済みで、参照したって何も無いよ、と。こんなの、見た瞬間に気付けなくっちゃだめだよなぁ……。悔しい。

言い訳をさせてもらえるならば、敗因は既存のコードはこれで動いていた、ということでしょうか。こんなのリリースして、二年以上も何の問題も無かったと言うことが信じられません。その既存のコードに若干手を入れた途端、メッセージ送信先の関数で渡した値が正常に取れなくなってはまっていたのですが、原因はどこにあるんだろうと延々と関係の無い事を探してしまいましたよ。修正前のコードとの違いとか、いくら見たってそれ自体が既に間違っているのだから見つかるわけもないのに……。

トイレから戻る途中で気付いた時はそのまま「空も飛べるはず!」とかなんとか言って窓から飛び出してみようかと思ってしまった。まったくもう。

ちなみにこれに関連して、ローカル変数の参照を戻り値にしてはいけない、みたいな話もあります。原因は同じ。詳しくはEffective C++(asin:4756118089) の31項を参照のこと。ちなみにここにある「関数の中でnewで初期化したポインタの参照先を返してはならない」というのも、このソフトは過去にやっていました。見つけた瞬間に全部修正しましたが、今思うともしかしたらあれがダークサイドに落ちるきっかけだったのかもしれない。本当に、バッドノウハウだかアンチパターンだか、そんなのばっかりです。引き継ぐ人の成長ために用意してくれていたんでしょうか?