Strukturált kivételkezelés

A strukturált kivételkezelés ( SEH  - Structured Exception Handling ) a Microsoft Windows operációs rendszer szoftveres és hardveres kivételeinek kezelésére szolgáló mechanizmus, amely lehetővé teszi a programozóknak a kivételkezelés vezérlését, és egyben hibakereső eszköz is [1] .

Kivételek és kivételkezelés

Kivételt képez a program végrehajtása során bekövetkezett esemény, amely abnormálisan vagy helytelenül viselkedik. Kétféle kivétel létezik: a hardver, amelyet a processzor hoz létre , és a szoftver, amelyet az operációs rendszer és az alkalmazási programok generálnak . A strukturált kivételkezelési mechanizmus lehetővé teszi a szoftveres és hardveres kivételek azonos kezelését.

Megvalósítás

Kulcsszavak

A mechanizmust a Microsoft csak fordítói szinten támogatja a nem szabványos szintaktikai konstrukciók __tryés . A kulcsszó a kód egy olyan szakaszának kiemelésére szolgál, amelyben a kivétel dobását egy vagy több blokk kezeli . A blokkban lévő kód mindig végrehajtásra kerül, függetlenül a többi blokktól és [2] . __except__finally__try__except__finally__try__except

Használati példa C és C++ nyelven

__próbáld meg { // védett kód, // amely egy SEH keretben van elhelyezve } __except ( kivételszűrő ) { _ // kivételkezelő } __végre { // kód, ami mindenképpen lefut }

A kivételszűrők lehetnek közönséges függvények, amelyek három állandó kifejezést adnak vissza: [3]

  • EXCEPTION_EXECUTE_HANDLER - jelzi ennek a kezelőnek a képességét a kivétel kezelésére. Egy ilyen érték fogadásakor az operációs rendszer leállítja a releváns kivételkezelők keresését, és a verem feltekerése után átadja a vezérlést az elsőnek, amelyik az EXCEPTION_EXECUTE_HANDLER értéket adta vissza.

  • EXCEPTION_CONTINUE_EXECUTION - hibajavítást jelez. A rendszer ismét a kivételt dobó utasításra adja át az irányítást, mert várhatóan ezúttal nem fog kivételt dobni. [négy]
  • EXCEPTION_CONTINUE_SEARCH - azt jelzi, hogy a veremben magasabban található megfelelő kezelő. Ugyanakkor ennek az értéknek a visszaadása azt jelezheti, hogy a hibát nem kezelték. [3]

Felhasznált szerkezetek és mechanizmusok

Bármely folyamatban minden szál egy regisztert (16 bites választó ) használ, hogy egy szál információs blokkfs adatszerkezetére mutató mutatót tároljon, amely információkat tartalmaz az adott szálról. Ez a struktúra egy mutatót tárol a hivatkozott listában az utoljára regisztrált _EXCEPTION_REGISTRATION_RECORD struktúrára , amely tartalmaz egy mutatót a kivételkezelőre és egy mutatót az előző _EXCEPTION_REGISTRATION_RECORD bejegyzésre . [5] A szál létrehozásakor az operációs rendszer hozzáad egy alapértelmezett kivételkezelőt, amelyet a . kernel32!UnhandledExceptionFilter

A visszahíváskezelő függvény prototípusa a következő:

EXCEPTION_DISPOSITION __cdecl _except_handler ( struct _EXCEPTION_RECORD * ExceptionRecord , void * EstablisherFrame , struct_CONTEXT * ContextRecord , _ void * DispatcherContext );

Minden alkalommal, amikor a programozó a konstrukciót használja __try, az _EXCEPTION_REGISTRATION_RECORD szerkezet új példánya, amely az msvcrt.dll könyvtár _except_handler3 függvényére mutat , hozzáadódik a szál vereméhez . A blokkkód __excepthívása __finallya _except_handler3-ból történik. A blokk végén a __tryfordító olyan kódot ad hozzá, amely eltávolítja az aktuális _EXCEPTION_REGISTRATION_RECORD bejegyzést, és visszaállítja a mutató értékét fs:0az előző bejegyzéshez.

Kivétel esetén a rendszer a megszakításkezelők teljes láncán sorban végighalad. Minden kezelő egy értéket ad vissza, jelezve, hogy képes-e kezelni ezt a kivételt vagy sem. Az elérhető kivételkezelők listájának végére mutató mutató FFFFFFFFaz utolsó kezelő utáni veremben található érték. Ha a rendszer megtalálja a kívánt kezelőt, akkor az irányítás átkerül rá. Ugyanakkor, miután megtalálta a felmerült kivételre vonatkozó megfelelő kezelőt, az operációs rendszer nem adja át azonnal az irányítást, hanem ismét egymás után hívja a lánc összes kezelőjét a zászlóval EH_UNWINDING, hogy tisztítsák meg (hívja a destruktort ) . [4] Ha a programozó által beállított kivételkezelő szűrők egyike sem adta vissza az EXCEPTION_EXECUTE_HANDLER vagy EXCEPTION_CONTINUE_EXECUTION értéket, akkor az UnhandledExceptionFilter alapértelmezett kivételkezelő szűrő, amelyet a szál futásra készülésekor regisztrál, végrehajtódik.

Kezelő hívás

Kivétel esetén az operációs rendszer nem közvetlenül hívja meg a kivételszűrőt (amely felelős azért, hogy egy adott kezelő kezeli-e a bekövetkezett kivételt vagy sem), hanem átadja a címét a függvénynek _except_handler3, ahonnan a szűrő függvény meghívásra kerül. . A következő adatstruktúrát használja: [6]

struct _EXCEPTION_REGISTRATION { struct _EXCEPTION_REGISTRATION * prev ; void ( * kezelő )( PEXCEPTION_RECORD , PEXCEPTION_REGISTRATION , PCONTEXT , PEXCEPTION_RECORD ); struct hatókörtábla_bejegyzés * hatókörtábla ; int trylevel ; int_ebp ; _ PEXCEPTION_POINTERS xpointers ; };

A mező *scopetableegy struktúrák tömbjének címére mutat scopetable_entry, a trylevel integer mező pedig egy indexre mutat ebben a tömbben. A mező _ebptartalmazza a verem keretmutató értékét, amely az EXCEPTION_REGISTRATION struktúra létrehozása előtt létezett. [7] A függvény _except_handler3meghívja a szükséges szűrőt, és a kezelő meghívása előtt letekercseli (megtisztítja) a veremet a függvény segítségével ntdll.dll!RtlUnwind.

Ha a programozó által telepített kezelők egyike sem járult hozzá a kivétel kezeléséhez, akkor egy függvényt hívunk UnhandledExceptionFilter, amely ellenőrzi, hogy a folyamat fut-e a hibakereső alatt , és tájékoztatja, ha elérhető. [7] A függvény ezután meghívja az alapértelmezett kezelőszűrőt (amelyet a függvény állít be, SetUnhandledExceptionFilterés mindig az EXCEPTION_EXECUTE_HANDLER értéket adja vissza). [7] Ezután az operációs rendszer beállításaitól függően vagy a debugger, vagy az NtRaiseHardError függvény meghívódik, ami hibaüzenetet jelenít meg. [7]

Jegyzetek

  1. Strukturált kivételkezelés (Windows) . Letöltve: 2010. május 5. Az eredetiből archiválva : 2010. szeptember 25..
  2. A strukturált kivételkezelésről (Windows) . Letöltve: 2010. május 5. Az eredetiből archiválva : 2011. február 28..
  3. 1 2 Bevezetés a SEH strukturált kivételkezelésbe (holt link) . Hozzáférés dátuma: 2012. december 26. Az eredetiből archiválva : 2014. március 27. 
  4. 1 2 WASM.IN Win32 SEH belül (1. rész) . Letöltve: 2018. április 5. Az eredetiből archiválva : 2018. április 5..
  5. SEH működtetése Win32 környezetben . Letöltve: 2010. május 1. Az eredetiből archiválva : 2015. szeptember 24..
  6. WASM.IN Win32 SEH belülről (2. rész) . Letöltve: 2018. április 5. Az eredetiből archiválva : 2018. április 5..
  7. 1 2 3 4 WASM.IN Win32 SEH belülről (3. rész) . Letöltve: 2018. április 5. Az eredetiből archiválva : 2018. április 5..