0

I have a program that loads a NativeAot compiled dll into a process, I was able to unload the module with some hacky approach. However, I recently discovered a problem, that is, the Window exception dispatcher calls into the handler in the NativeAot module even after it was unloaded, no matter where the exception is thrown, causing access violation.

Pseudo code:

HMODULE module = LoadLibraryA("Aot.dll");

// Code that terminates .NET runtime thread and unload dll
.......

// Throw and catch an exception
    try {
        throw exception("argh"); // Access violation executing location 0x00007FF97C8E69B0.
    }
    catch(exception ex){
        cout << "Caught" << endl; // Handler never called
    }

Stack trace from visual sutdio:

    00007ff97a3a69b0() -> This is a function in the unmapped module
    ntdll.dll!RtlpCallVectoredHandlers()
    ntdll.dll!RtlDispatchException()
    ntdll.dll!KiUserExceptionDispatch()
    main()

Any idea on why this is happening and what solution/hack I can use will be appreciated!

Sardelka
  • 354
  • 3
  • 9
  • From the names of the functions in the stack trace, it's apparent that the DLL registered a vectored exception handler. The DLL is not designed to be unloaded, and forcing it to unload is inevitably going to stumble over a long tail of problems like this. – Raymond Chen Feb 19 '23 at 15:07
  • Thanks for the hint, I discovered the AddVectoredExceptionHandler winapi shortly after I posted this question. I hooked this function, and indeed it was called by the runtime with the exact same address – Sardelka Feb 19 '23 at 15:31

1 Answers1

0

As Raymond Chen pointed out in the comments (much appreciated), .NET registeres a vectored exception handler with AddVectoredExceptionHandler.

I hooked this api and check the module of the handler with GetModuleHandleEx during unload, then unregisters it. Now the problem is gone.

There's a link to a demo in the answer of the question linked above.

Sardelka
  • 354
  • 3
  • 9
  • Note that this is just a hack on top of a hack. Someday, it will break (it might already be broken in some subtle way we haven't yet discovered) and you will have to add a third hack. This is not the way to ship production code. – Raymond Chen Feb 20 '23 at 11:27
  • @RaymondChen Thanks for your suggestion. But I'm well aware of the instability and impractibility of this solution. To clarify, this was never meant for production use, it's used for a small experimental hobby project that injects code into game process and I wish to use .NET as the scripting model/platform. – Sardelka Feb 20 '23 at 12:53
  • 1
    Somebody started [a list of other things that prevent the DLL from unloading](https://github.com/dotnet/corert/pull/7011#issuecomment-519403322) but the list is just a start. One of those other things may cause trouble too, or something that even isn't on the list. – Raymond Chen Feb 20 '23 at 14:38