Verhalten unterscheidet zwischen nicht verwalteten Debugbreak und gemischten (unmanaged + verwaltet) Anwendung?
-
26-09-2019 - |
Frage
Nehmen Sie die folgenden einfachen Quelle (name it test.cpp):
#include <windows.h>
void main()
{
DebugBreak();
}
kompilieren und verknüpfen diese mit den folgenden Befehlen:
cl /MD /c test.cpp
link /debug test.obj
Wenn TEST.EXE jetzt ausgeführt wird (auf einem 64-Bit-Windows-7-System), den folgenden Dialog erhalten:
Nun fügen Sie die folgende Quelldatei (Name es test2.cpp):
void hello()
{
}
Und kompilieren und verknüpfen diese zusammen mit der ersten Quelle, wie diese:
cl /MD /c test.cpp
cl /MD /c /clr test2.cpp
link test.obj test2.obj
Beachten Sie, dass wir die hallo-Funktion nicht einmal angerufen haben, wir verknüpfen es nur in.
Jetzt läuft TEST.EXE wieder (auf dem gleichen 64-Bit-Windows-7-System). Statt der Dialog oben gezeigt, können Sie diese:
Offenbar in .NET Framework Verknüpfung macht Debugbreak verhalten sich anders. Warum ist das? Und wie kann ich wieder das alte Verhalten Debugbreak zurück? Ist dies möglicherweise ein Windows 7 oder 64-Bit-spezifisches Verhalten?
Eine Neben Bemerkung deutlich machen, warum ich will Debugbreak verwenden: wir haben einen eigenen assert-Rahmen (so etwas wie die SuperAssert von John Robbins Debuggen von Windows-Anwendungen Buch), und ich verwende die Debugbreak-Funktion, so der Entwickler in springen der Debugger (oder öffnen Sie ein neues Debugger), wenn es ein Problem gibt. Jetzt gibt es nur die einfache Popup und keine Möglichkeit mehr zum Debugger zu springen.
Als alternative Lösung I eine Division durch Null oder einen Schreibvorgang zu ungültiger Adresse durchführen könnte, aber ich dieses eine weniger saubere Lösung finden.
EDIT: Dies ist den Call-Stack im zweiten Test (der einfache Dialog):
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()
Dies ist der Call-Stack im ersten Test (Dialog mit Auswahl "close" und "debug"):
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()
Der Unterschied beginnt in ntdll.dll!Executehandler2@20. In einer non-.net Anwendung ruft es ntdll.dll!@_EH4_CallFilterFunc
. In einer .NET-Anwendung ist Anrufe clr.dll!__except_handler4
.
Lösung
fand ich die Lösung auf der folgenden Seite: http: //www.codeproject. com / KB / debug / DebugBreakAnyway.aspx .
Statt nur Debugbreak schreiben, haben Sie die Debugbreak Anruf zwischen einem __try / __ ausgenommen Bau einzubetten, wie folgt aus:
__try
{
DebugBreak();
}
__except (UnhandledExceptionFilter(GetExceptionInformation()))
{
}
Offenbar die UnhandledExceptionFilter Funktion Griffe die Debugbreak Ausnahme von Standard, die in einem gemischten Modus appliation außer Kraft gesetzt zu sein scheint.
Sie nun den Original-Dialog wieder umkehren.