6

これはDelphiアプリケーションですが、一般的なWindowsプログラミングの質問だと思います。

私は週末にアプリケーションを(Delphi IDEで)実行したままにして、スタックオーバーフローを見つけるために戻ってきました。

スタックはこのように始まります...

:75c4417e kernel32.GetDriveTypeW + 0x23
:75c452ae kernel32.IsProcessorFeaturePresent + 0xa9
:75c45272 kernel32.IsProcessorFeaturePresent + 0x6d
:75c45248 kernel32.IsProcessorFeaturePresent + 0x43
:7678410b KERNELBASE.LoadStringBaseExW + 0xc7
:76678ed2 USER32.LoadStringW + 0x19
:0040c4ae LoadResString + $4A
uADStanDef.TADDefinition.Create(nil)
uADStanDef.TADDefinition.CreateTemporary
uADStanDef.TADConnectionDefTemporaryFactory.CreateObject
uADStanFactory.TADManager.CreateInterface((1050358107, 62550, 16757, (168, 100, 178, 87, 60, 74, 32, 21)),(no value),True)
uADStanFactory.ADCreateInterface((1050358107, 62550, 16757, (168, 100, 178, 87, 60, 74, 32, 21)),(no value),True)
uADCompClient.TADCustomConnection.Create($2DB7EB0)
fMainForm.TMainForm.ServerAliveTimerTimer($2E8DE38)    <========== my code
:004f1546 Winapi + $4F1546
:00461316 Winapi + $461316
:766762fa ; C:\Windows\syswow64\USER32.dll
:76676d3a USER32.GetThreadDesktop + 0xd7
:766777c4 ; C:\Windows\syswow64\USER32.dll
:7667788a USER32.DispatchMessageW + 0xf

そのため、タイマーが期限切れになり、(AnyDacコンポーネントの)新しいオブジェクトを作成していて、スタックがオーバーフローします。コードは間違いなくオブジェクトを解放します。確認したい方のために以下に追加しましたが、それは私の質問ではないと思います。

その後、スタックは続行されます

:7669cdfd ; C:\Windows\syswow64\USER32.dll
:7669cf5c ; C:\Windows\syswow64\USER32.dll
:766cf73c ; C:\Windows\syswow64\USER32.dll
:766cfa18 ; C:\Windows\syswow64\USER32.dll
:766cfb1f USER32.MessageBoxTimeoutW + 0x52
:766cfd15 USER32.MessageBoxExW + 0x1b
:766cfd57 USER32.MessageBoxW + 0x18
:00549986 Vcl + $549986
:00549aa2 Vcl + $549AA2
:00549873 Vcl + $549873
:00461316 Winapi + $461316
:766762fa ; C:\Windows\syswow64\USER32.dll
:76676d3a USER32.GetThreadDesktop + 0xd7
:766777c4 ; C:\Windows\syswow64\USER32.dll
:7667788a USER32.DispatchMessageW + 0xf

そのブロックが3000行(!)繰り返されると、それが何であるか、それが何をしているのかわかりません。その後終了します

StoreRoom.StoreRoom
:75c4339a kernel32.BaseThreadInitThunk + 0x12
:77eb9ef2 ntdll.RtlInitializeExceptionChain + 0x63
:77eb9ec5 ntdll.RtlInitializeExceptionChain + 0x36

私はその繰り返されるスタックのすべてを理解していません-誰かがアドバイスできますか?

(そして、私の例外処理がダイアログを表示していることに気付いたあなたの賢明な人のために、それはユーザーがOKをクリックすると閉じるTFormです)

私のコード:

procedure TMainForm.ServerAliveTimerTimer(Sender: TObject);
begin
   try
      ADConnection := TADConnection.Create(Self);  <======= stack overflow here
      ADConnection.DriverName := 'mysql';
      ADConnection.Params.Add('Server=' + MAIN_STOREROOM_IP_ADDRESS);  
      // other params, such as password, removed for posting
      ADConnection.Connected := True;

   except
      on E : Exception do
      begin
         ADConnection.Free();
         theDialogForm := TDialogFormForm.Create(Nil);
         theDialogForm.ShowTheForm('Database problem'+#13+#10+''+#13+#10+
                                   E.ClassName+#13+#10+E.Message);    
         StopTheApplication();   <===== just calls ExitProcess(0);
         Exit;                     as I had problems with Halt elsewhere in the code
      end;
   end;

   if isMainStoreRoom then
   begin
      CheckIfStoreRoomIsAlive(SECONDARY_STOREROOM_IP_ADDRESS);
   end
   else
   begin
      CheckIfStoreRoomIsAlive(MAIN_STOREROOM_IP_ADDRESS);
   end;

   try    // Now, update our own timestamp
      timestamp  := GetCurrentUnixTimeStamp();
      ADConnection.ExecSQL('UPDATE server_status SET alive_timestamp="' + IntToStr(timestamp) + '" WHERE ip_address="' + ipAddress + '"');

   except
      on E : Exception do
      begin
         ADConnection.Free();
         Exit;
      end;
   end;

   ADConnection.Free();
end;     // ServerAliveTimerTimer()
4

1 に答える 1

15

スタックオーバーフローはMessageBox()、ウィンドウメッセージの繰り返しに応じて何度も呼び出されることが原因です。内部的にMessageBox()は、独自のメッセージループを実行します。これは、明らかに同じメッセージを何度も処理およびディスパッチしています。これは、タイマーが誤っていることを示している可能性があります。最初にイベントハンドラーに入るときにタイマーを無効にし、OnTimer終了する前にタイマーを再度有効にすることを強くお勧めします。

別の注意点として、直接呼び出してStopTheApplication()はいけませんExitProcess()(またはHalt()直接呼び出してはいけません)。Application.Terminate()代わりに使用してください。

于 2012-09-24T02:21:18.450 に答える