Nested exception 'noise' with 64-bit

delphi package - automated exception handling
Post Reply
zunzster
Posts: 58
Joined: Wed Oct 29, 2008 3:43 am

Nested exception 'noise' with 64-bit

Post by zunzster »

When I trigger nested exceptions in 64-bit builds, I get seemingly spurious madExcept frames in the trace, rather than the expected frames, unlike what I get in the 32-bit build of the same code. Is this to be expected or am I doing something wrong?

Code: Select all

main thread ($1624): 
00777a25 AccredoSaturn64.exe Data.DB            2907 DatabaseError 
00777abe AccredoSaturn64.exe Data.DB            2913 DatabaseErrorFmt 
0136c4ab AccredoSaturn64.exe ProfaxTables      10438 TpfContext.InternalRelease 
0136dd3c AccredoSaturn64.exe ProfaxTables      10980 TpfContext.AbortTrans 
0136dcdf AccredoSaturn64.exe ProfaxTables      10967 TpfContext.RollbackTrans 
0139263f AccredoSaturn64.exe ProfaxTables      19735 TpfDatabase.RollbackTrans 
01ebe2cc AccredoSaturn64.exe dSPRuleEditCommon  1462 TdmSPRuleEditCommon.RecordSave 
01ec760f AccredoSaturn64.exe fSPRuleEditBase     751 TfrmSPRuleEditBase.PerformSave 
0154a2f2 AccredoSaturn64.exe fCustomEdit          93 TfrmCustomEdit.btnSaveClick 
005743b4 AccredoSaturn64.exe Vcl.Controls       7320 TControl.Click 
011af06d AccredoSaturn64.exe NLImages           2010 TCustomGlyphSpeedButton.Click 
01195d38 AccredoSaturn64.exe NLForm             1076 TnForm.CMChildKey 
0040b39e AccredoSaturn64.exe System                  TObject.Dispatch 
00573ae4 AccredoSaturn64.exe Vcl.Controls       7204 TControl.WndProc 
0057b1f4 AccredoSaturn64.exe Vcl.Controls       9972 TWinControl.WndProc 
006cef92 AccredoSaturn64.exe Vcl.Forms          4533 TCustomForm.WndProc 
0057e968 AccredoSaturn64.exe Vcl.Controls      11382 TWinControl.CMChildKey 
01231500 AccredoSaturn64.exe DataControls      16257 TnCustomPanel.CMChildKey 
0040b39e AccredoSaturn64.exe System                  TObject.Dispatch 
00573ae4 AccredoSaturn64.exe Vcl.Controls       7204 TControl.WndProc 
0057b1f4 AccredoSaturn64.exe Vcl.Controls       9972 TWinControl.WndProc 
0057e968 AccredoSaturn64.exe Vcl.Controls      11382 TWinControl.CMChildKey 
009d4d50 AccredoSaturn64.exe NLStandard         2462 TnGroupBox.CMChildKey 
0040b39e AccredoSaturn64.exe System                  TObject.Dispatch 
00573ae4 AccredoSaturn64.exe Vcl.Controls       7204 TControl.WndProc 
0057b1f4 AccredoSaturn64.exe Vcl.Controls       9972 TWinControl.WndProc 
0057e968 AccredoSaturn64.exe Vcl.Controls      11382 TWinControl.CMChildKey 
011c3ab0 AccredoSaturn64.exe CustomControl       870 TnCustomControl.CMChildKey 
010a1044 AccredoSaturn64.exe EditGrid           2088 TCustomEditGrid.CMChildKey 
0040b39e AccredoSaturn64.exe System                  TObject.Dispatch 
00573ae4 AccredoSaturn64.exe Vcl.Controls       7204 TControl.WndProc 
0057b1f4 AccredoSaturn64.exe Vcl.Controls       9972 TWinControl.WndProc 
011c3ff6 AccredoSaturn64.exe CustomControl      1055 TnCustomControl.WndProc 
010bf7d2 AccredoSaturn64.exe ListGrid           2366 TCustomListGrid.WndProc 
0057e968 AccredoSaturn64.exe Vcl.Controls      11382 TWinControl.CMChildKey 
011c3ab0 AccredoSaturn64.exe CustomControl       870 TnCustomControl.CMChildKey 
012045d5 AccredoSaturn64.exe DataControls       4461 TnCustomDropDown.CMChildKey 
0040b39e AccredoSaturn64.exe System                  TObject.Dispatch 
00573ae4 AccredoSaturn64.exe Vcl.Controls       7204 TControl.WndProc 
0057b1f4 AccredoSaturn64.exe Vcl.Controls       9972 TWinControl.WndProc 
011c3ff6 AccredoSaturn64.exe CustomControl      1055 TnCustomControl.WndProc 
0057358d AccredoSaturn64.exe Vcl.Controls       6982 TControl.Perform 
0057ef66 AccredoSaturn64.exe Vcl.Controls      11640 TWinControl.CNKeyDown 
0040b39e AccredoSaturn64.exe System                  TObject.Dispatch 
00573ae4 AccredoSaturn64.exe Vcl.Controls       7204 TControl.WndProc 
0057b1f4 AccredoSaturn64.exe Vcl.Controls       9972 TWinControl.WndProc 
011c3ff6 AccredoSaturn64.exe CustomControl      1055 TnCustomControl.WndProc 
0057a467 AccredoSaturn64.exe Vcl.Controls       9689 TWinControl.MainWndProc 
004ea8d3 AccredoSaturn64.exe System.Classes    13908 StdWndProc 
7759d8f1 ntdll.dll                                   KiUserCallbackDispatcher 
77346ba8 USER32.dll                                  SendMessageW 
006dd02a AccredoSaturn64.exe Vcl.Forms         10226 TApplication.IsKeyMsg 
006ddc44 AccredoSaturn64.exe Vcl.Forms         10573 TApplication.HandleMessage 
006dd38c AccredoSaturn64.exe Vcl.Forms         10313 TApplication.ProcessMessage 
006dd4a1 AccredoSaturn64.exe Vcl.Forms         10365 TApplication.HandleMessage 
006dd99f AccredoSaturn64.exe Vcl.Forms         10502 TApplication.Run 
02c2b575 AccredoSaturn64.exe AccredoSaturn      2510 initialization 
77445a4b kernel32.dll                                BaseThreadInitThunk 
main thread ($1624), inner exception level 1: 
>> EDatabaseError, RuleID surrogate -74 unknown 
00777a25 AccredoSaturn64.exe Data.DB         2907 DatabaseError 
7fefd681 KERNELBASE.dll                           WaitForSingleObjectEx 
007405a0 AccredoSaturn64.exe madExcept      14927 TIMEException.GetBugReport 
00738a5e AccredoSaturn64.exe madExcept      13730 TIMEException.GetBugReport_ 
022eeba3 AccredoSaturn64.exe fCustomMain     2284 TfrmCustomMain.MadExceptionHandlerException 
0070090b AccredoSaturn64.exe madExcept       4831 FireHandlers 
00700ff9 AccredoSaturn64.exe madExcept       4906 ReceiveFireHandlers 
0042f605 AccredoSaturn64.exe madTools         930 MsgHandlerWindowProc 
7759d8f1 ntdll.dll                                KiUserCallbackDispatcher 
77349e99 USER32.dll                               GetMessageW 
00736838 AccredoSaturn64.exe madExcept      13029 HandleException 
00743a54 AccredoSaturn64.exe madExcept      16116 InterceptAHandleExcept 
0057a48b AccredoSaturn64.exe Vcl.Controls    9695 TWinControl.MainWndProc 
004ea8d3 AccredoSaturn64.exe System.Classes 13908 StdWndProc 
7759d8f1 ntdll.dll                                KiUserCallbackDispatcher 
77346ba8 USER32.dll                               SendMessageW 
006dd02a AccredoSaturn64.exe Vcl.Forms      10226 TApplication.IsKeyMsg 
006ddc44 AccredoSaturn64.exe Vcl.Forms      10573 TApplication.HandleMessage 
006dd38c AccredoSaturn64.exe Vcl.Forms      10313 TApplication.ProcessMessage 
006dd4a1 AccredoSaturn64.exe Vcl.Forms      10365 TApplication.HandleMessage 
006dd99f AccredoSaturn64.exe Vcl.Forms      10502 TApplication.Run 
02c2b575 AccredoSaturn64.exe AccredoSaturn   2510 initialization 
77445a4b kernel32.dll                             BaseThreadInitThunk 
main thread ($1624), inner exception level 2: 
>> EDatabaseError, SPBREAK RuleID surrogate -78 unknown 
00777a25 AccredoSaturn64.exe Data.DB         2907 DatabaseError 
7fefd681 KERNELBASE.dll                           WaitForSingleObjectEx 
007405a0 AccredoSaturn64.exe madExcept      14927 TIMEException.GetBugReport 
00738a5e AccredoSaturn64.exe madExcept      13730 TIMEException.GetBugReport_ 
022eeba3 AccredoSaturn64.exe fCustomMain     2284 TfrmCustomMain.MadExceptionHandlerException 
0070090b AccredoSaturn64.exe madExcept       4831 FireHandlers 
00700ff9 AccredoSaturn64.exe madExcept       4906 ReceiveFireHandlers 
0042f605 AccredoSaturn64.exe madTools         930 MsgHandlerWindowProc 
7759d8f1 ntdll.dll                                KiUserCallbackDispatcher 
77349e99 USER32.dll                               GetMessageW 
00736838 AccredoSaturn64.exe madExcept      13029 HandleException 
00743a54 AccredoSaturn64.exe madExcept      16116 InterceptAHandleExcept 
0057a48b AccredoSaturn64.exe Vcl.Controls    9695 TWinControl.MainWndProc 
004ea8d3 AccredoSaturn64.exe System.Classes 13908 StdWndProc 
7759d8f1 ntdll.dll                                KiUserCallbackDispatcher 
77346ba8 USER32.dll                               SendMessageW 
006dd02a AccredoSaturn64.exe Vcl.Forms      10226 TApplication.IsKeyMsg 
006ddc44 AccredoSaturn64.exe Vcl.Forms      10573 TApplication.HandleMessage 
006dd38c AccredoSaturn64.exe Vcl.Forms      10313 TApplication.ProcessMessage 
006dd4a1 AccredoSaturn64.exe Vcl.Forms      10365 TApplication.HandleMessage 
006dd99f AccredoSaturn64.exe Vcl.Forms      10502 TApplication.Run 
02c2b575 AccredoSaturn64.exe AccredoSaturn   2510 initialization 
77445a4b kernel32.dll                             BaseThreadInitThunk 
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Nested exception 'noise' with 64-bit

Post by madshi »

It seems you have an exception handler "TfrmCustomMain.MadExceptionHandlerException" installed. Does that handler in line 2284 access "exceptIntf.BugReport"? And when those exceptions occur, is there a small "please wait" progress message box visible on screen?
zunzster
Posts: 58
Joined: Wed Oct 29, 2008 3:43 am

Re: Nested exception 'noise' with 64-bit

Post by zunzster »

Ah yes, we do have the aforementioned handler and indeed, it does access exceptIntf.BugReport on that line. I don't know about the 'please wait' - I don't recall seeing it but firing our nested exception test does indeed take a few seconds to produce the madExcept UI.

We use the handler to add a bunch of custom headers to our madExcept bugreports and log the madExcept errors into our pre-existing logging structure which dates back the stack tracing code I originally wrote before we switched to madExcept. There may well be a better way of achieving that without these side effects - it's pretty old code. What I find perplexing is why I don't get this issue in our 32-bit builds so it crept past me.

Here's the handler code for reference.

Code: Select all

procedure TfrmCustomMain.MadExceptionHandlerException(
  const exceptIntf: IMEException; var handled: Boolean);
var
  ParentForm: TCustomForm;
  Error: AnsiString;
  SystemPath: string;
  DataPath: string;
  CompanyLog: string;
begin
  { Always ensure that the system details are included in the bug report }
  if DefaultSession <> nil then
    begin
      SystemPath := IncludeTrailingBackslash(DefaultSession.SysPath);
      DataPath := DefaultDataBase.DataPath;
      if SameText('.\', CopyLeft(string(DataPath), 2)) then
        DataPath := SystemPath + CopyMiddle(DataPath, 3);

      if AppSettings.CompanyName <> '' then
        CompanyLog := 'company name      : ' + AppSettings.CompanyName + #13#10
      else
        CompanyLog := '';

      exceptIntf.BugReportHeader.Insert(0, 'system licencee', (DefaultSession.LicenseeName));
      exceptIntf.BugReportHeader.Insert(1, 'system serialno', (IntToStr(DefaultSession.SerialNo)));
      exceptIntf.BugReportHeader.Insert(2, 'company name', (AppSettings.CompanyName));
      exceptIntf.BugReportHeader.Insert(3, 'data path', (DataPath));
      exceptIntf.BugReportHeader.Insert(4, 'server path', (SystemPath));

      exceptIntf.bugReport := 'system licencee   : ' + DefaultSession.LicenseeName + #13#10 +
        'system serialno   : ' + IntToStr(DefaultSession.SerialNo) + #13#10 +
        CompanyLog +
        'data path         : ' + DataPath + #13#10 +
        'server path       : ' + SystemPath + #13#10 + exceptIntf.bugReport;
    end;

  if exceptObject is EAbort then
    handled := True
  else if (StdOut <> nil) and (exceptObject is Exception) then
    begin
      WriteExceptionLog(Exception(exceptObject), string(exceptIntf.bugReport));
{$IFDEF BugToClipboard}
      if DefaultSession.IsPrivate then
        Clipboard.AsText := exceptIntf.bugReport;
{$ENDIF}
      Error := AnsiString(exceptObject.ClassName + ': ' + Exception(exceptObject).Message + #13#10);
      StdOut.Write(Error[1], Length(Error));
      handled := True;
    end
  else if (exceptObject is FieldException) and not FieldException(exceptObject).FieldDestroyed then
    begin
      // Process any remaining messages to get the queue clear before the hint shows
      ProcessApplication(PM_QS_NO_INPUT);
      ShowErrorHint(FieldException(exceptObject).Message, FieldException(exceptObject).Field);
      handled := True;
    end
  else if exceptObject is EZFException then
    begin
      // Process any remaining messages to get the queue clear before the hint shows
      ProcessApplication(PM_QS_NO_INPUT);
      ShowStatusHint(EZFException(exceptObject).Message, nil, hsError);
      handled := True;
      exceptIntf.canContinue := True;
    end
  else if (exceptObject is NoLogException) or (exceptObject is EIdException) then
    begin
      if (Screen.ActiveForm <> nil) and (Screen.ActiveForm.FormStyle in [fsNormal, fsMDIForm]) then
        ParentForm := Screen.ActiveForm
      else
        ParentForm := Self;

      with TfrmProfaxError.CreateWithException(ParentForm, Exception(exceptObject)) do
        try
          ExecuteModal
        finally
          Release;
       end;
      handled := True;
      exceptIntf.canContinue := True;
    end
  else
    begin
      WriteExceptionLog(Exception(exceptObject), string(exceptIntf.bugReport));
{$IFDEF BugToClipboard}
      if DefaultSession.IsPrivate then
        Clipboard.AsText := bugReport;
{$ENDIF}
    end
end;
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Nested exception 'noise' with 64-bit

Post by madshi »

Can you easily reproduce the problem on your development PC? If so, it might make sense to try whether this problem goes away when removing your exception handler. That's not a solution, obviously, just a test.

Generally, accessing BugReport in an exception handler is "ok", but it does come at a disadvantage: madExcept is designed in such a way that the exception box is shown as quickly as possible. The bug report is created in the background. Calculating callstacks can be time consuming. So the exception box is shown before the callstacks are even available. The exception box is later updated when the bug report creation has completed (by the background thread). The purpose of this behaviour is to show the exception box as soon as possible, so the user doesn't see a "frozen"/crashed application without any reaction for any noticeable amount of time.

Now when you access exceptIntf.BugReport in your exception handler, basically you're forcing madExcept to calculate the bug report immediately. This effectively delays the showing of the exception box. Which is not a dramatic problem, but it's not optimal.

One way around this problem is to use the "epCompleteReport" parameter when registering the exception handler. This way your handler is called only after the bug report creation has already completed. As a result, you can access exceptIntf.BugReport without delaying the exception box creation. However, the exception box shown before your handler is called this way, so you lose some control. E.g. your handler can't stop the exception box from appearing, anymore, nor can it change the exception box layout or strings etc. If you need that, you could register two different handlers, one for epCompleteReport, and one other one. One handler then has control over the exception box (but shouldn't access exceptIntf.BugReport). The other handler is called once the bug report creation has completed.

Anyway, none of this should result in your application freezing. I've no idea why that happens right now. Have you tried running madTraceProcess.exe?
Post Reply