pleriche / FastMM4

A memory manager for Delphi and C++ Builder with powerful debugging facilities
447 stars 158 forks source link

Fix for spurious GetRawStackTrace Access Violations when using FastMM_FullDebugMode.dll #81

Open zunzster opened 5 years ago

zunzster commented 5 years ago

I've been getting intermittent spurious Access Violations on shutdown of my application from GetRawStackTrace in FastMM_FullDebugMode.dll which are just plain annoying.

I'm aware that this has been a known issue with FullDebugMode since 2014 (or so). https://stackoverflow.com/questions/22685386/occasional-access-violation-in-fastmm4-debuggetmem

In my case, I've determined that it's due to IsValidCallSite having an out-of-date MemoryPageAccessMap as a DLL which was at the address in question has just been unloaded during finalization for a unit, however one of it's return addresses is still sitting in a non-overwritten stack slot when DebugFreeMem is called.

I have a patch to FastMM_FullDebugMode.dpr that uses LdrRegisterDllNotification to add a DLL unload watcher to handle these cases and update the cache and thus avoid these access violations. It seems to work in that my reliably triggerable AV is now gone.

Ldr Dll Notifications are a documented internal NTDLL.DLL API that has existed since Windows Vista and are used by a number of low level tools and emulators for various purposes. Microsoft has scary warnings that they may remove them at any time but they are still there unchanged 13 years later in Windows 10 so you can make of that what you will.

https://docs.microsoft.com/en-us/windows/win32/devnotes/dll-load-notification

If others are bothered by these A/Vs like I am (and I can see a number of issues where developers have bumped into them and been confused by them), I've created a fork of FastMM4 and committed the code changes so others can see and evaluate them for the own use.

My code uses LoadLibrary/GetProcessAddress against NTDLL.DLL to check for the necessary Ldr APIs since that way anything earlier than Vista will just skip the new code. Similarly, if Microsoft does remove these APIs in a later Windows version for engineering reasons, the code will see that they are gone and not attempt to use them.