Search code examples
c++visual-studio-2015inline-assemblyseh

Inline asm assigning to 'FS:0': handler not registered as safe handler


I am trying to follow this article on Win32 Structured Exception handling. The article is quite old, but still considered a very good introduction to the subject.

I am trying to compile a code sample from the article reproduced below -

//==================================================
// MYSEH - Matt Pietrek 1997
// Microsoft Systems Journal, January 1997
// FILE: MYSEH.CPP
// To compile: CL MYSEH.CPP
//==================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

DWORD  scratch;

EXCEPTION_DISPOSITION
__cdecl
_except_handler(
    struct _EXCEPTION_RECORD *ExceptionRecord,
    void * EstablisherFrame,
    struct _CONTEXT *ContextRecord,
    void * DispatcherContext )
    {
    unsigned i;

    // Indicate that we made it to our exception handler
    printf( "Hello from an exception handler\n" );

    // Change EAX in the context record so that it points to someplace
    // where we can successfully write
    ContextRecord->Eax = (DWORD)&scratch;

    // Tell the OS to restart the faulting instruction
    return ExceptionContinueExecution;
    }

int main()
{
    DWORD handler = (DWORD)_except_handler;

    __asm
    {                           // Build EXCEPTION_REGISTRATION record:
        push    handler         // Address of handler function
        push    FS:[0]          // Address of previous handler
        mov     FS:[0],ESP      // Install new EXECEPTION_REGISTRATION
    }

    __asm
    {
        mov     eax,0           // Zero out EAX
        mov     [eax], 1        // Write to EAX to deliberately cause a fault
    }

    printf( "After writing!\n" );

    __asm
    {                           // Remove our EXECEPTION_REGISTRATION record
        mov     eax,[ESP]       // Get pointer to previous record.
        mov     FS:[0], EAX     // Install previous record
        add     esp, 8          // Clean our EXECEPTION_REGISTRATION off stack
    }

    return 0;
}

On compiling it with "cl", it seems to produce an executable, but also throws the following errors:

myseh.cpp(42) : warning C4733: Inline asm assigning to 'FS:0': handler not registered as safe handler
myseh.cpp(56) : warning C4733: Inline asm assigning to 'FS:0': handler not registered as safe handler

The executable crashes and it doesn't look like the custom exception handler is doing its job. Searching the internet seems to suggest that I need to register my custom exception handler function as a safe exception handler. I am not a professional developer. But I'd like to follow the article nevertheless. I need some guidance on how to get a working executable.

I am using Visual Studio 2015 on Windows 10.


Solution

  • From description of C4733 warning:

    Inline asm assigning to 'FS:0' : handler not registered as safe handler

    A function modifying the value at FS:0 to add a new exception handler may not work with Safe Exceptions, because the handler may not be registered as a valid exception handler (see /SAFESEH).

    To resolve this warning, either remove the FS:0 definition or turn off this warning and use .SAFESEH to specify the safe exception handlers.

    This basically means that you are trying to use handler that will be not registered as safe SEH handler in resulting executable image.
    Depending on your linker settings it may or may not be executed.

    By default linker produces table of safe handlers, but it doesn't know that your _except_handler is exception handler and therefore it won't put it to table of safe SEH handlers. To solve it you have basically two options:

    • Mark your function as safe handler using .safeseh MASM directive.
      You will have to put it into separate ASM file as these directives aren't supported by inline assembly.

    • Use /SAFESEH:NO switch to instruct linker to not create table of safe handlers.
      This way will be any SEH handler in your executable treat as safe handler by OS.

    I'd suggest to look at /SAFESEH linker switch and .safeseh MASM directive documentation for further information.

    More information about safe SEH handlers can be found in this article:

    The general idea is to collect handlers' entry points in a designated read-only table and have each entry point verified against this table for exceptions prior to control being passed to the handler.