Strukturerad undantagshantering ( SEH - Structured Exception Handling ) är en mekanism för att hantera program- och hårdvaruundantag i Microsoft Windows operativsystem som tillåter programmerare att kontrollera undantagshantering, och är också ett felsökningsverktyg [ 1 ] .
Ett undantag är en händelse under programkörning som gör att det beter sig onormalt eller felaktigt. Det finns två typer av undantag: hårdvara som genereras av processorn och programvara som genereras av operativsystemet och applikationsprogrammen . Den strukturerade undantagshanteringsmekanismen låter dig hantera både program- och hårdvaruundantag på samma sätt.
Mekanismen stöds endast av Microsoft på kompilatornivå genom implementering av icke - standardiserade syntaxkonstruktioner __tryoch . Nyckelordet används för att markera en kodsektion där ett undantag kommer att hanteras av ett eller flera block . Koden i blocket kommer alltid att exekveras oavsett andra block och [2] . __except__finally__try__except__finally__try__except
Användningsexempel i C och C++
__prova { // skyddad kod, // som är placerad i en SEH-ram } __except ( undantagsfilter ) { _ // undantagshanterare } __slutligen { // kod som ska köras ändå }Undantagsfilter kan vara vanliga funktioner som returnerar tre konstanta uttryck: [3]
Varje tråd i vilken process som helst använder ett register (16-bitars väljare ) fsför att lagra en pekare till en datastruktur för trådinformationsblock som innehåller information om den tråden. Denna struktur lagrar en pekare till den senast registrerade _EXCEPTION_REGISTRATION_RECORD- strukturen i den länkade listan , som inkluderar en pekare till undantagshanteraren och en pekare till föregående _EXCEPTION_REGISTRATION_RECORD- post . [5] När en tråd skapas lägger operativsystemet till en standardundantagshanterare som anropas av . kernel32!UnhandledExceptionFilter
Prototypen för återuppringningshanterarens funktion är som följer:
EXCEPTION_DISPOSITION __cdecl _except_handler ( struct _EXCEPTION_RECORD * ExceptionRecord , void * EstablisherFrame , struct_CONTEXT * ContextRecord , _ void * DispatcherContext );Varje gång programmeraren använder konstruktionen __tryläggs en ny instans av strukturen _EXCEPTION_REGISTRATION_RECORD, som pekar på funktionen _except_handler3 i biblioteket msvcrt.dll , till i trådens stack . Blockkod __exceptanropas __finallyfrån _except_handler3. I slutet av blocket __trylägger kompilatorn till kod som tar bort den aktuella _EXCEPTION_REGISTRATION_RECORD-posten och återställer värdet på pekaren fs:0till den föregående posten.
När ett undantag inträffar, itererar systemet genom hela kedjan av avbrottshanterare i sekvens. Varje hanterare returnerar ett värde som anger om den kan hantera detta undantag eller inte. Pekaren till slutet av listan över tillgängliga undantagshanterare är värdet som FFFFFFFFfinns på stacken efter den sista hanteraren. Om systemet hittar den önskade hanteraren överförs kontrollen till den. Samtidigt, efter att ha hittat den relevanta hanteraren för undantaget som har uppstått, överför operativsystemet inte omedelbart kontrollen till det, utan anropar återigen sekventiellt alla hanterare längs kedjan med flaggan EH_UNWINDINGför att städa upp (ringa förstöraren ) . [4] Om inget av de undantagshanterarfilter som ställts in av programmeraren returnerade EXCEPTION_EXECUTE_HANDLER eller EXCEPTION_CONTINUE_EXECUTION, exekveras UnhandledExceptionFilter standardexcepthanterarens filter, som registreras när tråden förbereds för att köras.
När ett undantag inträffar anropar operativsystemet inte direkt undantagsfiltret (som är ansvarigt för om en viss hanterare kommer att hantera undantaget som har inträffat eller inte), utan skickar sin adress till funktionen _except_handler3, varifrån filterfunktionen anropas . Den använder följande datastruktur: [6]
struct _EXCEPTION_REGISTRATION { struct _EXCEPTION_REGISTRATION * föregående ; void ( * hanterare )( PEXCEPTION_RECORD , PEXCEPTION_REGISTRATION , PCONTEXT , PEXCEPTION_RECORD ); struct scopetable_entry * scopetable ; int trylevel ; int_ebp ; _ PEXCEPTION_POINTERS xpekare ; };Fältet *scopetablepekar på adressen till en array av strukturer scopetable_entryoch heltalsfältet på försöksnivån pekar på ett index i denna array. Fältet _ebpinnehåller värdet för stackrampekaren som fanns innan strukturen EXCEPTION_REGISTRATION skapades. [7] Funktionen _except_handler3anropar det önskade filtret och, innan han anropar hanteraren, lindar (rensar) stacken med funktionen ntdll.dll!RtlUnwind.
Om ingen av hanterarna som installerats av programmeraren gick med på att hantera undantaget, anropas en funktion UnhandledExceptionFiltersom kontrollerar om processen körs under felsökaren och informerar den om den är tillgänglig. [7] Funktionen anropar sedan standardhanterarfiltret (som ställs in av funktionen SetUnhandledExceptionFilteroch som alltid returnerar EXCEPTION_EXECUTE_HANDLER). [7] Sedan, beroende på operativsystemets inställningar, anropas antingen felsökaren eller NtRaiseHardError-funktionen, vilket visar ett felmeddelande. [7]