![]() |
EAccessViolation führt zu unerwartetem APPCRASH (gelöst)
Hi,
für eine Konsolenanwendung die sich mit einem ActiveMQ Server verbindet und Nachrichten sendet habe ich versucht, bei einem temporären Ausfall des Servers (oder des Netzwerks) die Verbindung neu herzustellen und verwende dazu eine Schleife, die bei einer Exception verlassen und dann nach dem erneuten Verbindungsaufbau wieder gestartet wird. Anstatt die Schleife zu verlassen kommt es aber immer zu einem APPCRASH sobald der Server gestoppt wird. Hier erst einmal der Code für die Schleife mit der Exceptionbehandlung und der Code, der die Nachricht sendet:
Delphi-Quellcode:
Mit madExcept habe ich den Absturz untersucht und die Ursache ist anscheinend eine Access Violation. Im Stacktrace erscheint die Zeile 109 aus der ProducerLoop unit, dies ist die Zeile in der das "Break" steht mit dem die innere Schleife verlassen wird.
procedure TProducerLoop.Run;
begin while True do begin Connect; while True do begin try ProduceOneMessage; except on E: Exception do begin Break; // ---------------- Die innere Schleife soll bei einer Exception verlassen (stattdessen APPCRASH) end; end; end; Disconnect; end; end; procedure TProducerLoop.ProduceOneMessage; var Payload: string; begin Payload := Format('id [%d]', [Sequence.Value]); try Logger.Info('Produce ...'); Producer.Send(Queue, Payload); Logger.Info('Produced message: ' + Payload); Sequence.Increment; Sleep(100); except on E: Exception do begin Logger.Error('ProduceOneMessage', E); raise; end; end; end;
Code:
exception class : EAccessViolation
exception message : Access violation at address 00404A74 in module 'Producer.exe'. Read of address 00000000. main thread ($e3c): 00404a74 +170 Producer.exe System 44 +0 @HandleOnException 00404b5e +02a Producer.exe System 44 +0 @HandleFinallyInternal 777e3835 +0f4 ntdll.dll RtlUnwind 777aed27 +063 ntdll.dll bsearch 7779015e +00a ntdll.dll KiUserExceptionDispatcher 0045b0cf +033 Producer.exe SysUtils AppendChars 0040461a +002 Producer.exe System 44 +0 @ClassDestroy 0045d528 +03c Producer.exe SysUtils Exception.Destroy 00404198 +008 Producer.exe System 44 +0 TObject.Free 004531c9 +009 Producer.exe madExcept InterceptFreeExceptObject 00404d0a +016 Producer.exe System 44 +0 @DoneExcept 00482ebd +045 Producer.exe ProducerLoop 109 +12 TProducerLoop.Run 7779015e +00a ntdll.dll KiUserExceptionDispatcher 777aed27 +063 ntdll.dll bsearch 7779015e +00a ntdll.dll KiUserExceptionDispatcher 00499cc9 +025 Producer.exe IdTCPConnection 814 +3 TIdTCPConnection.CheckForGracefulDisconnect 0049ed83 +05b Producer.exe BTCommAdapterBaseIndy 424 +9 TBTCommAdapterBaseIndy.ConsumeHeartBeats 0049ef09 +055 Producer.exe BTCommAdapterBaseIndy 516 +6 TBTCommAdapterBaseIndy.ReadStompHeader 0049f626 +02a Producer.exe BTCommAdapterIndy 66 +1 TBTCommAdapterIndy.ReadFrame 0049f189 +055 Producer.exe BTCommAdapterBaseIndy 574 +5 TBTCommAdapterBaseIndy.ReadOneMessage 00477dce +066 Producer.exe BTStompClient 1232 +6 TBTStompClient.WaitForReceiptFrame 00475ca0 +140 Producer.exe BTStompClient 681 +22 TBTStompClient.Send 0047a426 +09e Producer.exe BTAbstractTransport 191 +12 TBTAbstractTransport.InternalSend 0047a6b1 +029 Producer.exe BTAbstractTransport 242 +3 TBTAbstractTransport.Send 00481d0e +126 Producer.exe BTConnection 1460 +40 TBTSession.Send 0047bda4 +0bc Producer.exe BTMessageProducer 251 +27 TBTMessageProducer.Send 0047bc73 +027 Producer.exe BTMessageProducer 209 +1 TBTMessageProducer.Send 0047d35e +022 Producer.exe BTMQProducer 160 +2 TBTMQProducer.InternalSend 0047d202 +03e Producer.exe BTMQProducer 125 +3 TBTMQProducer.Send 00482f62 +086 Producer.exe ProducerLoop 126 +5 TProducerLoop.ProduceOneMessage 00482e9b +023 Producer.exe ProducerLoop 105 +8 TProducerLoop.Run 004831e7 +033 Producer.exe ProducerUnit 38 +5 RunDemo 004a0754 +020 Producer.exe Producer 15 +3 initialization 75a7343b +010 kernel32.dll BaseThreadInitThunk Aus dem weiteren Stacktrace kann ich nicht erkennen warum die Schleife nicht verlassen wird. Ich teste als nächstes ob das Break in einem try ... except den Absturz verursacht. Die Entwicklungsumgebung ist Delphi 2009 auf Windows 7 (32 Bit). |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Wäre da nicht ein Exit besser? Ich kann es mit den paar Source Krümeln leider nicht testen.
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
Update:
Am Break liegt es nicht, mit diesem Code ergibt sich beim Stoppen des Servers ebenfalls ein APPCRASH:
Delphi-Quellcode:
Im Stacktrace erscheint die Zeile 111 aus der ProducerLoop unit, dies ist die Zeile in der das IsConnected := False steht mit dem die innere Schleife verlassen wird.
procedure TProducerLoop.Run;
begin while True do begin Connect; while IsConnected do begin try ProduceOneMessage; except on E: Exception do begin IsConnected := False; // ---------------- Die innere Schleife soll bei einer Exception verlassen (stattdessen APPCRASH) end; end; end; Disconnect; end; end;
Code:
exception class : EAccessViolation
exception message : Access violation at address 00404A74 in module 'Producer.exe'. Read of address 00000000. main thread ($b50): 00404a74 +170 Producer.exe System 72 +0 @HandleOnException 00404b5e +02a Producer.exe System 72 +0 @HandleFinallyInternal 77e83835 +0f4 ntdll.dll RtlUnwind 77e4ed27 +063 ntdll.dll bsearch 77e3015e +00a ntdll.dll KiUserExceptionDispatcher 0045b0cf +033 Producer.exe SysUtils AppendChars 7584c538 +041 KERNELBASE.dll RaiseException 0040461a +002 Producer.exe System 72 +0 @ClassDestroy 0045d528 +03c Producer.exe SysUtils Exception.Destroy 00404198 +008 Producer.exe System 72 +0 TObject.Free 004531c9 +009 Producer.exe madExcept InterceptFreeExceptObject 00404d0a +016 Producer.exe System 72 +0 @DoneExcept 00482ece +04e Producer.exe ProducerLoop 111 +12 TProducerLoop.Run 77e3015e +00a ntdll.dll KiUserExceptionDispatcher 77e4ed27 +063 ntdll.dll bsearch 7584c538 +041 KERNELBASE.dll RaiseException 77e3015e +00a ntdll.dll KiUserExceptionDispatcher 7584c538 +041 KERNELBASE.dll RaiseException 00491dee +016 Producer.exe IdStack 894 +1 TIdStack.RaiseLastSocketError 00491d59 +015 Producer.exe IdStack 868 +2 TIdStack.CheckForSocketError 0048df39 +025 Producer.exe IdStackBSDBase 444 +1 TIdStackBSDBase.Receive 0049320e +012 Producer.exe IdSocketHandle 321 +1 TIdSocketHandle.Receive 0049d843 +02b Producer.exe IdIOHandlerStack 431 +2 TIdIOHandlerStack.ReadDataFromSource 00497142 +0e2 Producer.exe IdIOHandler 1698 +28 TIdIOHandler.ReadFromSource 0049d367 +00b Producer.exe IdIOHandlerStack 243 +1 TIdIOHandlerStack.Connected 0049736b +017 Producer.exe IdIOHandler 1775 +8 TIdIOHandler.CheckForDataOnSource 0049ed86 +04e Producer.exe BTCommAdapterBaseIndy 421 +6 TBTCommAdapterBaseIndy.ConsumeHeartBeats 0049ef19 +055 Producer.exe BTCommAdapterBaseIndy 516 +6 TBTCommAdapterBaseIndy.ReadStompHeader 0049f636 +02a Producer.exe BTCommAdapterIndy 66 +1 TBTCommAdapterIndy.ReadFrame 0049f199 +055 Producer.exe BTCommAdapterBaseIndy 574 +5 TBTCommAdapterBaseIndy.ReadOneMessage 00477dce +066 Producer.exe BTStompClient 1232 +6 TBTStompClient.WaitForReceiptFrame 00475ca0 +140 Producer.exe BTStompClient 681 +22 TBTStompClient.Send 0047a426 +09e Producer.exe BTAbstractTransport 191 +12 TBTAbstractTransport.InternalSend 0047a6b1 +029 Producer.exe BTAbstractTransport 242 +3 TBTAbstractTransport.Send 004813fa +126 Producer.exe BTConnection 1460 +40 TBTSession.Send 0047f4bc +0bc Producer.exe BTMessageProducer 251 +27 TBTMessageProducer.Send 0047f38b +027 Producer.exe BTMessageProducer 209 +1 TBTMessageProducer.Send 0047ba1a +022 Producer.exe BTMQProducer 160 +2 TBTMQProducer.InternalSend 0047b8be +03e Producer.exe BTMQProducer 125 +3 TBTMQProducer.Send 00482f72 +086 Producer.exe ProducerLoop 128 +5 TProducerLoop.ProduceOneMessage 00482ea5 +025 Producer.exe ProducerLoop 107 +8 TProducerLoop.Run 004831f7 +033 Producer.exe ProducerUnit 38 +5 RunDemo 004a0754 +020 Producer.exe Producer 15 +3 initialization 7574343b +010 kernel32.dll BaseThreadInitThunk |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Das Break verlässt nur die innere Schleife.
Danach kommt ein Disconnect, welches vermutlich einen Fehler verursachen wird. Prüfe vor dem Disconnect, ob IsConnected True ist. |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
Ich seh es so wie Jasocul, das nicht das Break der Fehler ist sondern das was danach passiert.
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
ot
Ich habe da mal eine Frage, Du beginnst mit " while True do", worauf bezieht sich "True" ? /ot |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
als Breakpoint habe ich die Zeile mit IsConnected := False gesetzt. Dort stoppt das Programm dann wie erwartet, aber von dort geht es mit F8 sofort aus der Prozedur heraus in das finally der aufrufenden Methode.
Delphi-Quellcode:
ProducerLoop := TProducerLoop.Create(BROKER_URL, QUEUE_NAME);
try ProducerLoop.Run; // die Run-Prozedur wird bei einer Exception verlassen ... finally ProducerLoop.Free; // ... und daher das Programm hier fortgesetzt end; |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
Ginge es so eventuell?
Delphi-Quellcode:
procedure TProducerLoop.Run;
begin while True do begin if not IsConnected then Connect; while IsConnected do begin try ProduceOneMessage; except on E: Exception do begin Break; // hier fehler oder auch nicht, schau mal. end; end; end; if IsConnected then Disconnect; end; end; |
AW: EAccessViolation führt zu unerwartetem APPCRASH
k.A. was die ursprüngliche Exception auslöst ... Warum kommt niemand auf die Idee erstmal danach zu sehen?
Nja, wenn irgendwas einen der Stacktraces oder anderen Speicher schrottet, dann kann danach sonstwas kaputt sein und mit etwas Glück auch das ganze Programm abrauchen. |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
Delphi-Quellcode:
Die ursprüngliche Version - ohne IsConnected - ist aber völlig ausreichend. Den langen Umweg über IsConnected habe ich nur verwendet um das "Break" als Ursache des APPCRASH auszuschliessen. Der Code mit Break benötigt keine weitere Variable für den Abbruch der Schleife, ist funktional identisch, und leichter lesbar:
procedure TProducerLoop.Connect;
begin while True do try CreateProducer; Logger.Info('Connected %d', [GetCurrentThreadID]); IsConnected := True; Exit; except on E: Exception do begin Sleep(1000); end; end; end;
Delphi-Quellcode:
procedure TProducerLoop.Run;
begin while True do begin Connect; while True do begin try ProduceOneMessage; except on E: Exception do begin Break; end; end; end; Disconnect; end; end; |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
Fehler im sonstigen Code, der einen beschädigten Stack verursacht, ist natürlich nicht leicht zu finden. Sobald ich etwas mehr Zeit habe, schreibe ich eine simple Testanwendung, die nur versucht den Port des Servers zu öffnen. Spanned wird es wenn das dann funktioniert. Ursachen für Stackschäden zu finden ist sicher kein Ponyhof :) |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
Delphi-Quellcode:
So solltest Du aus Deinen Endlosschleifen rauskommen ohne Crash, oder?
procedure TProducerLoop.Run;
Label MyBreak; begin while True do begin Connect; while True do begin try ProduceOneMessage; except on E: Exception do begin Goto MyBreak; end; end; end; Disconnect; MyBreak: end; end; |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
Füge doch hier und da ein ShowException(E, ExceptAddr); ein um zu sehen ob woanders ein Fehler übersehen wurde.
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
Stacktrace Schäden hmmm.... ich habe mal etwas gegoogelt und bin bei
![]() Auch ohne dieses Tool gibt es einen kleinen Source ![]() Noch mehr google führte mich hier ![]() |
AW: EAccessViolation führt zu unerwartetem APPCRASH
Zitat:
|
AW: EAccessViolation führt zu unerwartetem APPCRASH
Problem gelöst: es lag an einem raise E; anstatt raise; in einem on E: Exception Handler Block
Delphi-Quellcode:
Wenn dort anstatt dem raise E; einfach nur raise; steht, funktioniert die Exceptionbehandlung wie gewohnt.
function TBTMQProducer.InternalSend(const AMessage: IMessage;
const Destination: IDestination; const CompletionListener: ICompletionListener): IMQProducer; begin try Producer.Send(Destination, AMessage); CompletionListener.OnMessage(AMessage); except on E: Exception do begin CompletionListener.OnException(AMessage, E); raise E; // ------- < end; end; end; Zu diesem Thema habe ich diese Seiten gefunden: ![]() ![]() Fazit: raise; ist korrekt. Mit einem versehentlichen raise E; hat man Stunden oder Tage spannenden Debuggings vor sich ;) |
AW: EAccessViolation führt zu unerwartetem APPCRASH (gelöst)
Boing, ja da sucht man sich einen Wolf! Es freut mich das Du es hinbekommen hast, an absolut anderer Quelle :thumb:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:29 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz