【问题标题】:Catching exit(1);捕捉出口(1);
【发布时间】:2009-03-08 10:04:47
【问题描述】:

我有一个 MFC SDI 应用程序,它在启动期间加载一个 DLL。我只能查看源代码并使用 DLL,但不能更改和重新编译它。

现在的情况是,每当 DLL 遇到错误时,它都会调用 exit(),如下所示。

bool Func()
{
  // .. do something here

  if (error) { exit(999); }
}

在我的 MFC 应用程序中,我设置了 SetUnhandledExceptionFilter 来处理所有异常,并且还创建了一个 MiniDump 用于调试目的。

所以现在的问题是,每当 DLL 遇到任何错误时,它只会使用状态码 999 调用 exit(),而我的 ExceptionFilter 不会捕获它,因此没有为 PostMortem 调试创建 MiniDump。

我想知道是否:
1. 我的全局异常处理程序是否有其他方法可以捕获此问题?
2. 我可以覆盖 exit() 函数,以便在调用它时,我调用它“throw(”error遇到!“)”并且我的全局异常处理程序可以捕获它。
3. 我尝试在我的 MFC 应用程序中使用 atexit(),借此我注册另一个函数以在 DLL 调用 exit() 时抛出错误。但这似乎也不起作用。

我真正想做的是,每当 DLL 遇到错误时,我希望生成一个 MiniDump,以便我可以进行事后调试。在这种情况下还有什么其他可能有效的方法吗?

谢谢。

【问题讨论】:

    标签: exception visual-c++ dll exit minidump


    【解决方案1】:

    检查 DLL 的符号导入表。

    您也许可以在运行时将其重新映射到您选择的函数。

    怎么做(假设有出口):

    大多数 DLL 都通过跳转表使用符号导入。如果你在调用者上设置断点,你会看到它调用了一个长跳转指令。跳转表是一个 PAGE_EXECUTE_READWRITE 页,因此您可以简单地用自己的地址覆盖跳转表的那个槽。

    跳转表的位置会有所不同,但它始终是与加载地址的恒定偏移量,因此是从任何函数指针到 GetProcAddress 找到的 DLL 的恒定偏移量。

    当然,所有这些都假设 DLL 永远不会改变。可能有一种方法可以在运行时找到所有这些东西,但我不知道你会怎么做。

    哦,你不能从 exit() 返回。你必须跳远。

    【讨论】:

      【解决方案2】:

      这是我编写的一个宏,用于在 exit() 函数中放置断点:

      Imports System.IO
      
      ' Sets breakpoints on all exit functions.  useful for catching library code that 
      ' calls exit in the debugger.
      Sub AddBreakpointsToExit()
          Dim bp As EnvDTE.Breakpoint
          Dim bps As EnvDTE.Breakpoints
      
          Dim envVar As String = "VS90COMNTOOLS"
          Dim comnTools As String = System.Environment.GetEnvironmentVariable(envVar)
          If (String.IsNullOrEmpty(comnTools)) Then
              Throw New System.Exception("Environment variable '" + envVar + "' doesn't exist.")
          End If
          Dim filePath As String = System.IO.Path.Combine(comnTools, "..\..\VC\crt\src\crt0dat.c")
      
          ' set exit function names and line #s:
          Dim exitFunctions(0 To 4) As String
          exitFunctions(0) = "exit"
          exitFunctions(1) = "_exit"
          exitFunctions(2) = "_cexit"
          exitFunctions(3) = "_c_exit"
      
          ' line numbers are based on the Visual Studio 2008 definition.
          ' TODO: check and add options if 2005 or 2010 are differen.t
          Dim exitLines(0 To 4) As Integer
          exitLines(0) = 412
          exitLines(1) = 420
          exitLines(2) = 427
          exitLines(3) = 434
      
          ' set breakpoints:
          For i = 0 To 3 Step 1
              bps = DTE.Debugger.Breakpoints.Add(File:=filePath, Line:=exitLines(i))
          Next i
      
      End Sub
      

      【讨论】:

        【解决方案3】:

        我还没有找到解决方案,但是这可能是您的atexit 处理程序没有帮助的一个原因:dll 可能静态链接到 CRT。这意味着 exit() 的代码直接内置到 dll 中,这将为其提供自己的退出处理程序私有列表,因此从您的主机进程中注册的 atexit 处理程序将永远不会被看到。如果您能够从 dll 中调用 atexit()(这将很难安排),它可能会起作用。

        只是一个猜测 - 希望对您有所帮助。

        【讨论】:

          【解决方案4】:

          当进程正常退出时,每个 DLL 都会收到一个DLL_PROCESS_DETACH notification。编写自己的 DLL 并专门用于捕获此通知怎么样?

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-11-04
            • 2012-08-24
            • 1970-01-01
            • 2011-10-22
            • 1970-01-01
            • 2012-09-30
            • 2019-04-01
            相关资源
            最近更新 更多