【问题标题】:Delphi 7 exception not caughtDelphi 7异常未捕获
【发布时间】:2010-09-16 05:57:50
【问题描述】:

我一直在处理一些非常复杂的遗留代码,在收集大量数据时会崩溃。我一直无法找到崩溃的确切原因,并且正在尝试不同的方法来解决它,或者至少可以很好地恢复。我做的最后一件事是将崩溃的代码包含在一个

try
  ...
except
  cleanup();
end;

只是为了让它正常运行。但清理工作永远不会完成。什么情况下异常不会被捕获?这可能是由于某些内存溢出或其他原因,因为该应用正在收集相当多的数据。

哦,我在添加try 之前遇到的异常是“访问冲突”(还有什么?),CPU 窗口指向非常低的地址。任何想法或指示将不胜感激!

【问题讨论】:

    标签: delphi exception


    【解决方案1】:

    我的代码的初始化和终结块中出现了异常,madExcept 甚至似乎都没有捕捉到。如果您在该 try 块内引用外部 DLL,则可能会发生这种情况。我不确定原因。

    实际上(感谢@Gung 告诉我我的古老答案毫无价值),我最近在古老的 O'Reilly Delphi Tome 中读到了这篇文章。您应该将 SysUtils 作为第一个(或在您的非标准内存管理器单元之后的第二个)放在您的主窗体的 DPR 中,以便它驻留在内存中并具有所有它的异常捕获优点。否则,如果它是从其他单元加载的,它也将与该单元一起卸载,您可以告别内置的异常处理。

    【讨论】:

      【解决方案2】:

      我曾经在调用一些使用安全调用调用约定的 COM 对象时遇到这种奇怪的行为。此对象/方法可能会引发 EOleException,而不是被客户端代码上通常的 try/except 捕获。 您应该捕获一个 EOleException 并正确处理它。

      try
      ...
      except
      on E: EOleException do
      ...
      end;
      

      我不知道这是否是您面临的问题。但如果是的话,我建议你看一下Implement error handling correctly,这是一篇关于delphi 异常处理的非常清晰的帖子。

      您还可以启用您的 IDE 调试选项以在发生德里异常时停止并监控堆栈跟踪。

      【讨论】:

        【解决方案3】:

        这可能是一个 DLL 还是一个 COM 对象?如果是这样,则主机应用程序可能将 FPUExcpetion 掩码设置为与 Delphi 习惯不同的东西。默认情况下,溢出会在 Delphi 中产生异常,但可以设置 FPUExcpetionmask 使其不会,并将值设置为 NAN。有关 FPUExceptionmask 的更多信息,请参阅 math.pas 单元

        【讨论】:

          【解决方案4】:

          你有很多很好的答案。我不得不追逐的最疯狂的问题来自巴里提到的堆栈损坏问题。我已经看到链接器页面上项目的“内存大小”部分发生了一些事情。我可能很迷信,但似乎更大并不一定更好。您可以考虑使用增强型内存管理器 FastMM4——它免费且非常有用。

          http://sourceforge.net/projects/fastmm/

          我已经将它与 d7 一起使用,并发现了一些对陈旧指针和其他邪恶事物的访问。

          您可能还希望创建一种方法来跟踪有效对象和/或以其他方式检测代码,以使代码在工作时自行检查。

          当我看到对 0x00001000 或更小的地址的访问时,我想到了对 nil 指针的访问。我的字符串列表:=无; myStringList.Clear;

          当我看到访问具有更大数字的其他地址时,我会想到过时的指针。

          当事情异常不稳定并且堆栈跟踪被证明是无稽之谈和/或变化很大时,我知道我有堆栈问题。有一次在 Controls.pas 中;下次它在 mmsys.pas 等中。

          对 DLL 使用错误的调用约定也确实会弄乱您的堆栈。这是因为从DLL调用/返回时参数传递/释放。

          MadExcept 将有助于找到此问题的根源,即使它显示出无稽之谈......你会赢任何一种方式,因为你会知道问题发生在哪里,或者你会知道你有一个堆栈问题。

          有没有什么测试框架可以用来锻炼它?我发现它非常非常强大,因为它使它完全可重复。

          我用这种方法解决了一些非常难看的问题。

          【讨论】:

            【解决方案5】:

            我将把 except 可能不起作用的原因留给Barry...

            但我强烈建议采用一种简单的策略来缩小发生这种情况的范围。 将大块切成较小的部分,由

            try
              OutputDebugString('entering part abc');
              ... // part abc code here
            except
              OutputDebugString('horror in part abc');
              raise;
            end;
            ...   
            try
              OutputDebugString('entering in part xyz');
              ... // part xyz code here
            except
              OutputDebugString('horror in part xyz');
              raise;
            end;
            

            并在旁边使用DebugView 运行您的代码...(适用于没有 GUI 的应用程序以及类似服务)。
            您将看到执行了哪个部分以及是否在其中捕获了异常。

            【讨论】:

              【解决方案6】:

              废弃的堆栈或堆栈溢出都可能对堆栈上的结构造成无法弥补的损害,Windows 中的结构化异常处理 (SEH) 使用这些结构来查找实际的异常处理程序。

              如果您在堆栈上的缓冲区中发生缓冲区溢出(例如,将静态数组作为局部变量但写入超出其末尾),并覆盖异常记录,那么您可以覆盖“next”指针,该指针指向堆栈上的下一个异常记录。如果指针被破坏,操作系统将无法找到下一个异常处理程序并最终到达您的包罗万象的处理程序。

              堆栈溢出是不同的:它们可以完全阻止调用函数,因为每个函数调用都需要至少一个双字的堆栈空间作为返回地址。

              【讨论】:

              • 这似乎接近事实,我正在进一步调查。谢谢!
              【解决方案7】:

              “非常低的地址”可能意味着有人试图在一个实际上并不存在的对象上调用虚拟方法(即“无”)。例如:

              TStringList(nil).Clear;

              不过,第一部分非常神秘。我不知道这是怎么发生的。

              我认为您应该尝试使用madExcept 捕获该异常。它从来没有让我失望过。 (免责声明:我没有使用 D7。)

              【讨论】:

              • 我第二次使用madExcept,我在Delphi 7中成功使用过。
              • 第三次使用madExcept。它非常易于使用,只需安装到 IDE 并为您的项目启用即可。
              猜你喜欢
              • 1970-01-01
              • 2021-10-05
              • 1970-01-01
              • 2023-03-06
              • 1970-01-01
              • 2010-09-28
              • 2012-05-31
              相关资源
              最近更新 更多