为什么即使被全局异常钩子捕获,程序也会崩溃?

别杰连科

问题摘要:中的某些代码UartComm.OnGetIdRES()引发ERangeError,使我的程序崩溃。这个错误不是问题,重要的是为什么我的应用程序全局异常钩子捕获异常,但是我的程序仍然崩溃。我希望钩子能够捕获并处理所有未处理的异常;该程序应继续运行。

这是负责全局异常挂钩的单元:

unit LogExceptions;

interface
uses
  Windows, SysUtils, Classes, JclDebug, JclHookExcept;

procedure AppendToLog(Msg: String; const LogFileLevel: TLogFileLevel);

implementation
uses Main;

procedure HookGlobalException(ExceptObj: TObject; ExceptAddr: Pointer;
                              OSException: Boolean);
var
  Trace: TStringList;
  DlgErrMsg: String;
begin
  { Write stack trace to `error.log`. }
  Trace := TStringList.Create;
  try
    Trace.Add(
        Format('{ Original Exception - %s }', [Exception(ExceptObj).Message]));
    JclLastExceptStackListToStrings(Trace, False, True, True, False);
    Trace.Add('{ _______End of the exception stact trace block_______ }');
    Trace.Add(' ');

    Trace.LineBreak := sLineBreak;
    LogExceptions.AppendToLog(Trace.Text, lflError);

    { Show an dialog to the user to let them know an error occured. }
    DlgErrMsg := Trace[0] + sLineBreak +
      Trace[1] + sLineBreak +
      sLineBreak +
      'An error has occured. Please check "error.log" for the full stack trace.';
    frmMain.ShowErrDlg(DlgErrMsg);
  finally
    Trace.Free;
  end;
end;

procedure AppendToLog(Msg: String; const LogFileLevel: TLogFileLevel);
{ .... irrelevant code ....}

initialization
  Include(JclStackTrackingOptions, stTraceAllExceptions);
  Include(JclStackTrackingOptions, stRawMode);

  // Initialize Exception tracking
  JclStartExceptionTracking;

  JclAddExceptNotifier(HookGlobalException, npFirstChain);
  JclHookExceptions;

finalization
  JclUnhookExceptions;
  JclStopExceptionTracking;

end.

(如果它是有帮助这里的链接JclDebug.pasJclHookExcept.pas

我要做的所有激活钩子的操作就是将添加LogExceptions到中的interface uses列表中Main.pas

现在,这是崩溃的分步说明:

  1. 执行进入 UartComm.OnGetIdRES()
  2. ERangeError当我尝试设置提高Length动态数组的-7

    SetLength(InfoBytes, InfoLength);

  3. 我们进入LogExceptions.HookGlobalException()此时在IDE中显示的调用堆栈是这样的(我遗漏了内存地址):

    ->  LogExceptions.HookGlobalException
        :TNotifierItem.DoNotify
        :DoExceptNotify
        :HookedRaiseException
        :DynArraySetLength
        :DynArraySetLength
        :@DynArraySetLength
        UartComm.TfrmUartComm.OnSpecificRES // This method runs `OnGetIdRES()`
        UartComm.TfrmUartComm.OnSpecificPktRX
        UartComm.TfrmUartComm.DisplayUartFrame
        UartComm.TfrmUartComm.UartVaComm1RxChar
        VaComm.TVaCustommComm.HandleDataEvent
        VaComm.TVaCommEventThread.DoEvent
        { ... }
        { ... Some low-level calls here .... }
    
  4. 我们一离开HookGlobalException调试器,就会抛出一个对话框:

    引发带有消息“范围检查错误”的异常类ERangeError

如果我按“继续”,程序仍处于冻结状态。如果没有调试器,程序此时将冻结。

  1. 如果单击“中断”并继续使用调试器,则执行过程将一直贯穿整个堆栈VaComm.TVaCommEventThread.DoEvent并执行以下行:

    Application.HandleException(Self);
    

之后,它什么也不做(我进入调试器例程,并且程序永远“运行”)。

即使我不对钩子使用JCL库,而是指向Application.OnException一些空例程,也会发生完全相同的事情。

为什么异常被钩子捕获,然后在钩子返回时重新引发?我如何抑制该异常,以使程序不会崩溃却可以继续运行?

更新:我取得了3个重大发现:

  • JCL挂钩实际上捕获了所有异常,无论是已处理还是未处理。这就是为什么GlobalExceptHook()在异常降到调用堆栈之前。
  • Application.OnException 在代码中的其他位置被重新分配。
  • Application.HandleException执行OnException(但是调试器没有向我显示,当我尝试进入内部时),那里有一行试图关闭COM端口。这是使我的程序的GUI冻结的那一行。

当我弄清楚一切后,我会写一个答案。

别杰连科

问题是UartComm.TfrmUartComm.UartVaComm1RxChar事件触发了。在此例程中引发未处理的异常时,执行将通过调用堆栈进行处理,直到到达为止Application.OnException

在内部,OnException我尝试使用来关闭COM端口VaComm1.Close()其中一部分Close()是调用以停止VaComm1线程并WaitFor()完成线程。但是请记住,UartVaComm1RxChar永不归来!永不完结!因此,这WaitFor()一直在等待。

解决方案是启用TTimer内部OnException并将VaComm1.Close()例程移到此Timer中。程序完成了对引发的异常的处理,并在事件完成后返回执行“ main”循环。现在,TTimer触发并关闭COM端口。

更多细节在这里

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么即使使用错误边界,我的React应用程序也会崩溃?

为什么gcov会导致程序崩溃?

为什么这个 C 程序会崩溃?

为什么该程序无法捕获异常?

为什么即使在捕获错误后 fetch 也会返回?

为什么Akka HTTP路由会捕获我的异常?

全局错误捕获,以防止运行时异常导致程序崩溃

为什么应用程序会全局存储实例?

为什么当引发异常时应用程序不会崩溃

为什么FinderSync扩展程序在启动前会崩溃?

即使处理了未捕获的异常,Node.js程序也会退出

为什么在捕获异常后我的Java程序退出?

为什么异常处理程序无法捕获模式匹配失败?

为什么程序崩溃

Java未捕获的全局异常处理程序

Haxe未捕获的全局异常处理程序

即使异常被捕获,Lint 也会警告可能的异常

为什么 chrome 会崩溃?

为什么即使声明了全局变量,Javascript代码也会显示“未定义”?

为什么即使myLocation是全局变量,当onSuccess()终止时myLocation也会变为空?

即使在异常处理之后程序也会终止

即使我正在处理正在发生的错误,为什么我的nodejs服务器也会崩溃?

为什么即使不存在捕获括号,split 也会返回空字符串?

为什么即使捕获到错误也会向用户显示错误消息?

为什么对全局变量的不正确分配会提早引发异常?

为什么boost :: lexical_cast即使转换了值也会引发异常?

为什么即使使用了调用,组合框也会引发异常

为什么即使定义为 double 也会抛出此 numberformat 异常

为什么 Promise.all() 即使我 .catch() 也会抛出异常?