(toppers-users 240) Re: Windows のシミュレーションに失敗
Takayuki WAKABAYASHI
takayuki @ ertl.ics.tut.ac.jp
2001年 7月 29日 (日) 19:58:29 JST
豊橋技術科学大学の若林です。
「Windowsのシミュレーションに失敗」の問題が解決しましたので、
報告いたします。
先日頂いたデータにおかしな点が無かったので、
こちらでも同じ環境を再現してみましたところ、
同様の問題が起こることが判りました。
# Microsoft Windows NT Server 4.0 + ServicePack 4
# Microsoft Visual C++ 6.0 Enterprise
# Microsoft Internet Explorer 4.01
問題を追跡したところ、原因は呼び出し規約の違いによるものでした。
#単純にCALLBACKを付け忘れたという間抜けなミスでした
---8<---
場所
KeyEventTrapper (serial_console.c:170)
上記関数のプロトタイプ宣言 (serial_console.c:67)
修正
関数宣言にCALLBACK (または__stdcall)を入れる
#この問題はWinNT+SP4のみの組み合わせだけでなく、
#全てのWindowsプラットフォームで起こる可能性があります。
##USER32.DLLに依存するエラー
修正前 static LRESULT KeyEventTrapper(...省略...);
修正後 static LRESULT CALLBACK KeyEventTrapper(...省略...);
発見までの経緯
・スレッド追跡を行ったところ、処理を行うメインスレッドが
停止していることがわかった。
・問題発生時のスタック内容を調べたところ、スタックの中身が
破壊されていることが判った。
・スタック追跡を行ったところ、スタック内にKeyEventTrapper関数
を指すポインタがあることが判ったので、該当関数にブレークを
設置したところ、常に3回目の実行で停止することがわかった。
#3回目は1,2回目とは異なる関数から呼ばれており、その関数は
#呼出前にスタックポインタを待避していなかった
・3回目の実行を追跡したところ、関数への引数の一部(Msg)が呼び出し
元の戻り番地として扱われていることが判った。
・Windows内の関数のエピローグコードを調べたところ、全てスタック
フレームは呼出先が壊していることがわかった。(RET imm16命令)
・MSDNで呼出規約を調べたところ、全てのWindows関数は__stdcall呼出
でなければならないのに、当該関数は_cdeclのままになっていたこ
とが判った。
#_cdecl : スタックフレームの破棄は呼出元が行う
#__stdcall : スタックフレームの破棄は呼出先が行う
---8<---
Windows2000やWindows98で障害が出ていないところを見ると、
これらのUSER32.DLLは「アプリを書く人は仕様通りのものを
作ってこない」ことを仮定したDLL設計がなされているのでしょう。
大堀さん、ご報告 感謝いたします。
+----------------------------------------------+
| Takayuki WAKABAYASHI (わかばやし たかゆき) |
| mailto: takayuki @ ertl.ics.tut.ac.jp |
+----------------------------------------------+
| 豊橋技術科学大学 工学研究科 電子情報工学専攻 |
| 組込みリアルタイムシステム研究室 |
+----------------------------------------------+