Saturday 8 July 2017

Windows OS Loader Lock and Dllmain - Why we need it locked


Recently I was investigating the dos and donts with DllMain for a project of mine, especially with respect to initializing other dlls needed by my own dll.  I have see a fair no of questions as to why the loader lock is necessary.  I also came across this article which questioned the need for OS loader lock and a use case where  the loader lock had to be circumvented to implement the needed funcationality

http://www.lenholgate.com/blog/2004/09/why-does-windows-hold-the-loader-lock-whilst-calling-dllmain.html

One of the comments by Jonathan Clark in the blog post gives an explanation as to why the loader lock is needed.  To explain Jonathan Clark's reasoning, if the loader lock is released before DllMain is called, i.e. before the dll has finished initialization, some other thread can obtain a handle to the yet uninitialized dll using and then obtain the address for a function in that dll using GetProcAddress(), and call the function in the still uninitialized libraries to consequences that will have you lose your sleep.

Another reason why the OS loader lock is needed is the clash that can occur between a dll that is in the process of being unloaded, while another thread figures that the module still exists even though it is being unloaded.  For example, let's say we have 2 threads T1 and T2.  T1 calls FreeLibrary(), which before calling DllMain with the DETACH callbacks, releases the loader lock and is then preempted.  Thread T2 can see from the list of dlls mapped on the system, that this dll is still mapped/loaded/listed on the system, and consider the availability of the module for carrying out other tasks, which can include calling other functions in this module, while now T1 can start running again inside DllMain() and then the continue to have the module unmapped from memory.  Now T2 would be at a stage where it had just figured sometime back the module still exists, but the module is now unmapped, thus having T2 continue running under the wrong assumptions.