2

常に正常に動作していた既存のコード ( Jedi Windows Security LibraryTerminal Server ユニット)の問題をトラブルシューティングしています。いくつかの調査の後、問題の部分はWTSOpenServerへの呼び出しに帰着しました:

  while true do
  begin
      hServer := WTSOpenServer(PChar('server'));
      WTSCloseServer(hServer);
      hServer := 0;
  end;

ランダムな (しかし小さい) 数または実行の後、アプリ全体がクラッシュし、デバッグが難しくなります。私がすでに試したことは次のとおりです。

  • WTSOpenServer は (CreateProcessW のように) pServername パラメーターに書き込みません (実際、逆アセンブルを確認したところ、コピーが作成されます)
  • nil をパラメーターとして渡すと、コードは正常に実行されます (したがって、ローカルマシンで動作します)。
  • リモート サーバー、localhost、またはダミーを pServerName として使用すると、結果は常にクラッシュします (Vista 以降では、無効なサーバー名でも、ドキュメントに従って有効なハンドルが返されます)。
  • Delphi 2009 と 2010 の両方でテスト済み
  • 同じコードが Visual Studio (c++) で正常に動作します。
  • Visual Studio で逆アセンブリを確認し、Delphi から asm で WTSOpenServer を呼び出しました (そして、ハンドル型を C のようなポインターに変更しました)。

    hModule := LoadLibrary('wtsapi32.dll');
    if hModule = 0 then
      Exit;
    
    WTSOpenServer := GetProcAddress(hModule, 'WTSOpenServerW');
    if WTSOpenServer = nil then
      Exit;
    
    while true do
    begin
      asm
        push dword ptr pServerName;
        call dword ptr WTSOpenServer;
        mov [hServer], eax;
      end;
    
      hServer := nil;
    end;
    
  • WTSCloseServer への呼び出しを省略します

  • Windows 7 の x64 バージョンと x86 バージョンの両方でコードをテストする
  • Delphi デバッガーの代わりに外部デバッガーを使用します (その場合は正常に動作するように見えるので、何らかのタイミング/スレッド/デッドロックの問題であると推測されます)。
  • AddVectoredExceptionHandlerを追加すると、EXCEPTION_ACCESS_VIOLATION が表示されますが、スタックが破損しているように見えます。EIP は 1 であるため、どこで発生したかを判断できません。

現時点では、これをさらにトラブルシューティングする方法や説明を見つける方法がわかりません。

4

1 に答える 1

1

FullDebugMode で FastMM を使用してアプリケーションを実行してみてください。あなた/サードパーティのライブラリコードのバグのように見えます-メモリの上書き/バッファオーバーフローの可能性があります(sthのようにほとんど.GetMemはUnicodeString/Stringのような操作には小さすぎます.「動作」しますが、遅かれ早かれクラッシュします/ AV) .

大きなアプリを D2009 に移行するときに、似たような状況がいくつかありましたが、ほとんどの場合、Char=1 バイトという仮定が原因でした。時々非常に奇妙なことが起こりましたが、常に FullDebugMode が役に立ちました。例外は CreateProcessW でしたが、既知の/文書化された動作です。

アプリがメモリを上書きする場合に FullDebugMode を使用すると、それを解放すると、FastMM は割り当てられた場所で例外を発生させるため、このバグを簡単に追跡できます。割り当ての最初と最後にいくつかのバイトが追加されるため、上書きされたかどうかがわかります。

新しい/空の VCL プロジェクトでは再現できません。自分で試すことができます (このループは約 5 分間実行されます)。

uses JwaWtsApi32;
procedure TForm7.FormCreate(Sender: TObject);
var
  hServer: DWORD;
begin
  while true do
  begin
      hServer := WTSOpenServer(PChar('server'));
      WTSCloseServer(hServer);
      hServer := 0;
  end;
end;
于 2010-01-06T19:56:47.893 に答える