もう一度アトムリークとVCLのバグについて

はじめに


テープを覗いてみると、「原子誤用とVCLのわかりにくいバグ」という記事に出会いました。 アイデアを読んだ後、同じ分野の別の問題を説明するために立ち上がったが、この記事では説明していません。 私たちのチームは自分でそれを見つけましたが、これはすでに既知のVCLバグであることが判明しました。 Delphi 7で開発が進行中であり、新しいバージョンにバグがあるかどうかはわかりません。 以下のリンクから判断すると、そのまま修正があります。 明らかな理由により、バージョン7の修正を希望する理由はありません。



MrShoorの記事では、いわゆる Delphiアプリケーションが正しく完了せず、一部のアトムが削除されない場合のアトムテーブル。 アトミックテーブルを圧倒するために、アプリケーションを「強制的に強制終了」する必要はまったくないことがわかります。 起動して正しく閉じるだけで十分ですが、何回も続けて実行します。

これがどのように起こるか見てみましょう:



オーバーフローメカニズムの説明


「メモリ不足」のような別の苦情を受け取った後、原子の表がControlOfs <hexadecimal ID>の形式の要素で詰まっていることがわかりました。 これらの要素は各アプリケーションの開始時に表示され(アプリケーションサーバーは接続ごとに1つのインスタンスを起動します)、テーブルに永久に残ります。



Controls.pasのInitControlsのコードのセクションをもう一度考えてみましょう-上記の記事と同じです:



WindowAtomString := Format('Delphi%.8X',[GetCurrentProcessID]); WindowAtom := GlobalAddAtom(PChar(WindowAtomStrinjg)); ControlAtomString := Format('ControlOfs%.8X%.8X', [HInstance, GetCurrentThreadID]); ControlAtom := GlobalAddAtom(PChar(ControlAtomString)); RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));
      
      







一番最後の行も、見たところ、アトムを作成します。 新しいメッセージタイプを登録すると、新しいアトムがテーブルに追加され、そのたびに新しい名前が付けられます。 問題は、RegisterWindowsMessageがMSDNを参照することです。原則として、逆登録解除アクションを意味しません。 この機能により、複数のプログラムがいくつかのメッセージIDを一緒に使用できます。

RegisterWindowMessage関数は通常、2つの連携するアプリケーション間で通信するためのメッセージを登録するために使用されます。



2つの異なるアプリケーションが同じメッセージ文字列を登録すると、アプリケーションは同じメッセージ値を返します。 メッセージは、セッションが終了するまで登録されたままです。


これは深刻です 状況に影響を与えるレバレッジはありません。 このような原子をサードパーティのアプリケーションで閉じることは不可能です-この記事を書くように促した記事で提案されたプログラムは、ここでは無力です。 アトムテーブルには16ビット時代のルーツがあり、テーブルのサイズに制限を課しているため、この迷惑なバグにより、サーバー部分がすぐに乱れてしまいます。 システムを再起動せずにDelphiアプリケーションを起動することはできませんでした。



これは、1つのウィンドウからの単純なプログラムの「通常の開始-修正完了」を20回繰り返した後のアトムテーブルの例です。



赤で強調表示されている原子は、20回の打ち上げ直後に残った原子です。



このエラーは、たとえば次のような場所で説明されています。

詳細なエラーの説明

より簡潔なバグレポート

もちろん、 スタックオーバーフロー



解決方法


原子は事後的に削除できないため、その作成を防ぐ必要があります。 私たちのチームは、RegisterWindowMessageAへの呼び出しをインターセプトするIATフックを使用し、ControlOfs <something there>というタイプの名前のメッセージが記録された場合、代わりにすべてのアプリケーションで同じ他の識別子が記録されます。 判明したように、彼は一意である必要はありませんでしたが、これはバグレポートにも示されています



フックコードは、それを設定するメカニズムと同様に簡単です。 さらに、インターネット上には、Delphi for IATフック用の既製のライブラリがあります。 フック自体は、登録されているメッセージがControlOfsプレフィックスと一致しないかどうかをできるだけ迅速に確認するだけです。一致する場合は、RM_GetObjectInstanceに置き換えられます。



これが誰かが長くて難しいデバッグを避けるのに役立つことを願っています。



All Articles