【问题标题】:Behavior of DebugBreak differs between unmanaged and mixed (unmanaged+managed) application?DebugBreak 的行为在非托管和混合(非托管+托管)应用程序之间有所不同?
【发布时间】:2010-09-02 17:53:25
【问题描述】:

获取以下简单源(将其命名为 test.cpp):

#include <windows.h>

void main()
{
DebugBreak();
}

使用以下命令编译并链接它:

cl /MD /c test.cpp
link /debug test.obj

如果现在运行 TEST.EXE(在 64 位 Windows 7 系统上),您会看到以下对话框:

现在添加以下源文件(命名为 test2.cpp):

void hello()
{
}

然后编译并将它与第一个源链接在一起,如下所示:

cl /MD /c       test.cpp
cl /MD /c /clr  test2.cpp
link test.obj test2.obj

请注意,我们甚至没有调用 hello 函数,我们只是将其链接进去。

现在再次运行 TEST.EXE(在同一个 64 位 Windows 7 系统上)。您得到的不是上面显示的对话框,而是:

显然,.Net 框架中的链接使 DebugBreak 的行为有所不同。 为什么是这样?我怎样才能恢复旧的 DebugBreak 行为? 这可能是 Windows 7 或 64 位特定的行为吗?

附注说明我为什么要使用 DebugBreak:我们有一个自定义断言框架(类似于 John Robbin 的调试 Windows 应用程序书中的 SuperAssert),我使用 DebugBreak 函数以便开发人员可以跳转到如果有问题,调试器(或打开一个新的调试器)。现在只有简单的弹出窗口,不能再跳转到调试器了。

作为替代解决方案,我可以执行除零或写入无效地址,但我发现这是一个不太干净的解决方案。

编辑: 这是第二个测试(简单对话框)中的调用堆栈:

ntdll.dll!_NtRaiseHardError@24()  + 0x12 bytes  
ntdll.dll!_NtRaiseHardError@24()  + 0x12 bytes  
clrjit.dll!Compiler::compCompile()  + 0x5987 bytes  
clr.dll!RaiseFailFastExceptionOnWin7()  + 0x6b bytes    
clr.dll!WatsonLastChance()  + 0x1b8 bytes   
clr.dll!InternalUnhandledExceptionFilter_Worker()  + 0x29c bytes    
clr.dll!InitGSCookie()  + 0x70062 bytes 
clr.dll!__CorExeMain@0()  + 0x71111 bytes   
msvcr100_clr0400.dll!@_EH4_CallFilterFunc@8()  + 0x12 bytes 
msvcr100_clr0400.dll!__except_handler4_common()  + 0x7f bytes   
clr.dll!__except_handler4()  + 0x20 bytes   
ntdll.dll!ExecuteHandler2@20()  + 0x26 bytes    
ntdll.dll!ExecuteHandler@20()  + 0x24 bytes 
ntdll.dll!_KiUserExceptionDispatcher@8()  + 0xf bytes   
KernelBase.dll!_DebugBreak@0()  + 0x2 bytes 
test_mixed.exe!01031009()   

这是第一个测试中的调用堆栈(带有“关闭”和“调试”选项的对话框):

ntdll.dll!_ZwWaitForMultipleObjects@20()  + 0x15 bytes  
ntdll.dll!_ZwWaitForMultipleObjects@20()  + 0x15 bytes  
kernel32.dll!_WaitForMultipleObjectsExImplementation@20()  + 0x8e bytes 
kernel32.dll!_WaitForMultipleObjects@16()  + 0x18 bytes 
kernel32.dll!_WerpReportFaultInternal@8()  + 0x124 bytes    
kernel32.dll!_WerpReportFault@8()  + 0x49 bytes 
kernel32.dll!_BasepReportFault@8()  + 0x1f bytes    
kernel32.dll!_UnhandledExceptionFilter@4()  + 0xe0 bytes    
ntdll.dll!___RtlUserThreadStart@8()  + 0x369cc bytes    
ntdll.dll!@_EH4_CallFilterFunc@8()  + 0x12 bytes    
ntdll.dll!ExecuteHandler2@20()  + 0x26 bytes    
ntdll.dll!ExecuteHandler@20()  + 0x24 bytes 
ntdll.dll!_KiUserExceptionDispatcher@8()  + 0xf bytes   
KernelBase.dll!_DebugBreak@0()  + 0x2 bytes 
test_native.exe!00af1009()  

区别始于 ntdll.dll!Executehandler2@20。在非.net 应用程序中,它调用ntdll.dll!@_EH4_CallFilterFunc。在 .net 应用程序中调用 clr.dll!__except_handler4

【问题讨论】:

    标签: .net debugbreak


    【解决方案1】:

    我在以下页面找到了解决方案:http://www.codeproject.com/KB/debug/DebugBreakAnyway.aspx

    您必须在 __try/__except 构造之间嵌入 DebugBreak 调用,而不是仅仅编写 DebugBreak,如下所示:

    __try
       {
       DebugBreak();
       }
    __except (UnhandledExceptionFilter(GetExceptionInformation()))
       {
       }
    

    显然,UnhandledExceptionFilter 函数默认处理 DebugBreak 异常,这似乎在混合模式应用程序中被否决了。

    现在你又恢复了原来的对话框。

    【讨论】:

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