- 
                Notifications
    You must be signed in to change notification settings 
- Fork 114
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Actual behavior
Using CsWin32's AddVectoredExceptionHandler, when the handler callback is called by Windows, we get the message "Fatal error. Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code." printed to the console, and the program crashes with an ExecutionEngineException.
Expected behavior
The handler callback should not crash the program. In the example below, I show one way of getting the handler callback to work using RuntimeMethodHandle.GetFunctionPointer(). I don't understand why the CsWin32 version (or the other approaches I show below) are not working though. Maybe I'm missing something?
Repro steps
- NativeMethods.txtcontent:
AddVectoredExceptionHandler
RemoveVectoredExceptionHandler
- 
NativeMethods.jsoncontent (if present):
 N/A
- 
Any of your own code that should be shared? 
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.System.Diagnostics.Debug;
class Program
{
    public unsafe static void Main(string[] args)
    {
        if (!OperatingSystem.IsWindowsVersionAtLeast(5, 1, 2600))
            throw new InvalidOperationException();
        void* vehHandle;
        int x;
        // Comment/uncomment the following blocks to try different approaches.
        {
            // RuntimeMethodHandle.GetFunctionPointer: works as expected.
            var methodHandle = typeof(Program).GetMethod(nameof(MethodHandleVEH), BindingFlags.NonPublic | BindingFlags.Static)!.MethodHandle;
            RuntimeHelpers.PrepareMethod(methodHandle);
            // Note: this is not CsWin32's PInvoke; it's my own implementation. See below.
            vehHandle = AddVectoredExceptionHandler(1, methodHandle.GetFunctionPointer());
            Console.WriteLine($"MethodHandle handle: {(nint)vehHandle}");
            x = *(int*)0; // Should throw NullReferenceException.
            RemoveVectoredExceptionHandler(vehHandle);
        }
        {
            // CsWin32: ExecutionEngineException
            vehHandle = PInvoke.AddVectoredExceptionHandler(1, CsWin32VEH);
            Console.WriteLine($"CsWin32 handle: {(nint)vehHandle}");
            x = *(int*)0; // Should throw NullReferenceException, but there is an ExecutionEngineException first.
            PInvoke.RemoveVectoredExceptionHandler(vehHandle);
        }
        {
            // Unmanaged function pointer: ExecutionEngineException
            delegate* unmanaged<EXCEPTION_POINTERS*, int> funcPointer = &FunctionPointerVEH;
            vehHandle = AddVectoredExceptionHandler(1, (nint)funcPointer);
            Console.WriteLine($"Function Pointer handle: {(nint)vehHandle}");
            x = *(int*)0; // Should throw NullReferenceException, but there is an ExecutionEngineException first.
            RemoveVectoredExceptionHandler(vehHandle);
        }
        {
            // Marshal.GetFunctionPointerForDelegate: ExecutionEngineException
            var handlerDelegate = new VectoredExceptionHandler(DelegateVEH);
            vehHandle = AddVectoredExceptionHandler(1, Marshal.GetFunctionPointerForDelegate(handlerDelegate));
            Console.WriteLine($"Delegate handle: {(nint)vehHandle}");
            x = *(int*)0; // Should throw NullReferenceException, but there is an ExecutionEngineException first.
            RemoveVectoredExceptionHandler(vehHandle);
        }
    }
    static unsafe int MethodHandleVEH(EXCEPTION_POINTERS* e) => 0;
    static unsafe int CsWin32VEH(EXCEPTION_POINTERS* e) => 0;
    [UnmanagedCallersOnly] static unsafe int FunctionPointerVEH(EXCEPTION_POINTERS* e) => 0;
    static unsafe int DelegateVEH(EXCEPTION_POINTERS* e) => 0;
    [DllImport("Kernel32.dll")]
    static extern unsafe void* AddVectoredExceptionHandler(uint first, nint handlerAddress);
    [DllImport("Kernel32.dll")]
    static extern unsafe ulong RemoveVectoredExceptionHandler(void* handle);
    unsafe delegate int VectoredExceptionHandler(EXCEPTION_POINTERS* exceptionInfo);
}Context
- CsWin32 version: 0.3.106
- Target Framework: net8.0
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working