Am I being called from DllMain?

Lock; literal images 'r' us
Lock; literal images 'r' us
While Googling for an obscure Windows function the other day, I came across this fantastically useful repository of undocumented WinAPI functions, put together by Geoff Chappell. I’m not sure how I hadn’t discovered it before.

One of the functions that immediately caught my eye was LdrLockLoaderLock. I’d previously spent quite a few frustrating hours trying to figure out how to determine whether some code was being executed from DllMain, i.e. while in the loader lock, so I could avoid doing anything dodgy – or indeed, anything at all.

The case I was looking at was some logging library code that was used, amongst other things, to record the fact that DLLs were being unloaded. Unfortunately when this was called from DllMain, it sometimes caused a deadlock, for all the reasons we already know about. The library code was called from lots of DLLs, so it wasn’t feasible to fix all of the call sites, instead I had to make the logging a no-op when it’s not safe.

I’m embarrassed to say that my previous attempt to detect the lock involved some pretty heinous hackery. I worked out the memory address (the offset within ntdll.dll) where the loader lock critical section is located, cast that bit of memory to a CRITICAL_SECTION and tested it. I even had to provide the ability to change the offset based on the version of ntdll being used, in a vain attempt to reduce its fragility. Ouch. It was very nasty, and to be honest although it worked in the cases where I tested it, I was reluctant to release it.

Luckily, along comes LdrLockLoaderLock to save my blushes. It appears to give me exactly the functionality I need; you can pass a flag to tell it to return immediately if the lock’s already been taken, and there’s a status parameter that can be used to tell if you got the lock – whereupon you can call the corresponding LdrUnlockLoaderLock. Nice!

I wonder if this is what’s used by the Visual Studio loader lock managed debugging assistant to determine if your managed code is being run under the loader lock?