Comportamento di DebugBreak diversa tra (gestito gestito +) applicazione non gestito e misti?
-
26-09-2019 - |
Domanda
Prendere la seguente origine semplice (lo chiama test.cpp):
#include <windows.h>
void main()
{
DebugBreak();
}
compilare e linkare questo utilizzando i seguenti comandi:
cl /MD /c test.cpp
link /debug test.obj
Se PROVA.EXE è ora gestito (su un sistema Windows 7 64-bit), si ottiene la seguente finestra di dialogo:
Ora aggiungere il seguente file di origine (chiamarlo test2.cpp):
void hello()
{
}
E compilare e linkare questo insieme con la prima fonte, in questo modo:
cl /MD /c test.cpp
cl /MD /c /clr test2.cpp
link test.obj test2.obj
Si noti che non abbiamo nemmeno chiamare la funzione di ciao-, abbiamo appena legati in.
Ora eseguire nuovamente PROVA.EXE (sullo stesso sistema a 64 bit di Windows 7). Invece della finestra di dialogo mostrato sopra, si ottiene questo:
A quanto pare, il collegamento nel quadro Net rende DebugBreak comportano in modo diverso. Perchè è questo? E come posso ottenere di nuovo il vecchio DebugBreak comportamento indietro? È questo forse un comportamento specifico di Windows 7 o 64 bit?
Un lato-osservazione per chiarire il motivo per cui voglio usare DebugBreak: abbiamo un assert-quadro personalizzato (qualcosa di simile alla SuperAssert da applicazioni libro debug di Windows di John Robbin), e io uso la funzione DebugBreak modo lo sviluppatore può saltare in il debugger (o aprire un nuovo debugger) se c'è un problema. Ora c'è solo la semplice comparsa e nessuna possibilità di saltare al debugger più.
Come soluzione alternativa ho potuto eseguire una divisione per zero o una scrittura di indirizzo non valido, ma trovo questa una soluzione meno pulita.
Modifica Questo è lo stack di chiamate nella seconda prova (la semplice finestra di dialogo):
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()
Questo è lo stack di chiamate nella prima prova (dialogo con le scelte "chiuso" e "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()
La differenza inizia nel ntdll.dll!Executehandler2@20. In un'applicazione non-.net chiama ntdll.dll!@_EH4_CallFilterFunc
. In un'applicazione .NET è chiamate clr.dll!__except_handler4
.
Soluzione
ho trovato la soluzione nella seguente pagina: http: //www.codeproject. com / KB / debug / DebugBreakAnyway.aspx .
Invece di limitarsi a scrivere DebugBreak, è necessario incorporare la chiamata DebugBreak tra un __try / __ tranne la costruzione, in questo modo:
__try
{
DebugBreak();
}
__except (UnhandledExceptionFilter(GetExceptionInformation()))
{
}
A quanto pare, la funzione maniglie UnhandledExceptionFilter l'eccezione DebugBreak di default, che sembra essere oltrepassato in un appliation modalità mista.
Ora si ottiene la finestra originale di nuovo.