Skip to main content

Command Palette

Search for a command to run...

Windows Exception Handling

Updated
4 min read
Windows Exception Handling

Agenda :

what is exception ?

what causes an exception ?

what are the type of exception handler exist ?

who sees it first ?

What windows does by default ?

when you need to register handlers ?

What is windows exception (at OS level) ?

  • An exception is an event that stops the normal execution of code

  • It typically originates from one of two places :

    • Hardware (the CPU)

    • Software

Hardware (CPU) : The CPU tries to execute an instruction but cannot

Example : Access Violation , Integer Divide by Zero

  •       int* ptr = nullptr; // Pointer is NULL (address 0) 
          *ptr = 42; // CRASH! Writing to address 0 is illegal
    

    The CPU executes the instruction to write 42 to address 0x0. The CPU hardware refuses and triggers an interrupt. The Windows Kernel catches this interrupt and converts it into an Exception Code (like 0xC0000005).

    Software : Your program explicitly tells the OS to trigger an exception using the windows API function RaiseException().

The Exception Handling Hierarchy (Order of Precedence) :

When that exception occurs, Windows looks for a handler in a specific order. It does not go straight to your try/catch block immediately.

Order of Precedence :

  1. Debugger (if attached) : If a debugger is attached , windows pauses execution and lets the debugger know --> this is called as the first chance exception

  2. Vectored Exception Handler (VEH) : if no debugger handles it (or none is attached), windows pauses the execution and calls VEH

    1. Priority : Highest priority within the application.

    2. Scope : Global (Process-wide). It handles exceptions from any thread.

    3. Registration : You must manually register this using AddVectoredExceptionHandler.

  3. Structured Exception Handling :

    1. Priority : Lower than VEH

    2. Scope : Local (Thread based and stack based) , It looks for try , catch , except blocks in your specific function and then checks the function that called it , and so on (unwinding the stack)

  4. UnHandledExceptionFilter : if no SEH handles it , the system calls a top level filter

  5. Default system handler : if nothing else handles it , windows takes over .

Do we need to register the handlers (or) windows do this by default ? we need to register the handlers only if we want to prevent the application from getting crashed or log the error before dying. If we are okay with the program closing when it crashes, you do not need to write any handling code.

If you do not register any handlers (VEH or SEH) and your code crashes: 1. Windows invokes the Default Exception Handler. 2. This handler typically collects crash data (Windows Error Reporting). 3. It displays the "Application has stopped working" dialog or simply kills the process silently. 4. The application exits immediately. It does not recover.

Examples :

0x01 - The Default Behavior : No Handler

This program will just crash and close.

#include <iostream>

int main() {
    int* badPtr = nullptr;
    *badPtr = 10; // Exception triggered here by CPU
    return 0;
}

0x02 - Structured Exception handler

This is the standard way to handle errors in specific blocks of code

#include <windows.h>
#include <iostream>

int main() {
    __try {
        // Protected code block
        int* badPtr = nullptr;
        *badPtr = 10; 
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        // Windows found this handler on the stack!
        std::cout << "Caught an Access Violation! The program is saved." << std::endl;
    }

    std::cout << "Program continues execution..." << std::endl;
    return 0;
}

0x03 - Vectored exception Handler

This handler is called before the SEH block above, even if the crash happens deep inside a function.

#include <windows.h>
#include <iostream>

// Your custom VEH function
LONG WINAPI MyVectoredHandler(PEXCEPTION_POINTERS pExceptionInfo) {
    if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
        std::cout << "[VEH] I saw the crash FIRST (Global Handler)!" << std::endl;

        // OPTIONAL: You can try to fix it, or tell Windows to keep searching.
        // EXCEPTION_CONTINUE_SEARCH tells Windows to let SEH (the next handler) try.
        return EXCEPTION_CONTINUE_SEARCH; 
    }
    return EXCEPTION_CONTINUE_SEARCH;
}

int main() {
    // Register the VEH
    AddVectoredExceptionHandler(1, MyVectoredHandler);

    __try {
        int* badPtr = nullptr;
        *badPtr = 10; 
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        std::cout << "[SEH] Caught locally." << std::endl;
    }

    return 0;
}

Output of the VEH example:

I saw the crash FIRST (Global Handler)! (VEH runs first) Caught locally. (Because VEH returned CONTINUE_SEARCH, SEH got a chance).

Want to dive deeper into Windows internals?

Check out my other blog posts for more deep dives!