FreeLibraryAndExitThread – Why and when do we need it?

Let’s say we are writing an asynchronous function in our dll that does certain task in background.

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    // This is a new thread.
    return 0;
}
VOID AsyncFunction()
{
    CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
}

What if an external dll calls our AsyncFunction and unloads our dll (by calling FreeLibrary) before the thread has finished processing. It would result in an access violation (AV) because the dll containing the code (which is being executed by the thread) has unloaded.

Sequence of events:

  • External caller loads test.dll using LoadLibrary . Ref count on test.dll is 1.
  • External caller calls AsyncFunction. This spawns a thread to do the async task and returns quickly to the caller.
  • Caller does not wait for the thread to finish execution and calls FreeLibrary.
  • Calling FreeLibrary brings the ref count on test.dll down to 0 and the loader unloads test.dll.
  • Since test.dll is out of memory and the thread is still executing its code, this leads to AV.

Most of the time we try to solve this issue is by calling LoadLibrary on ourselves and FreeLibrary when the work of the thread is done. Calling LoadLibrary on ourselves increments the dll ref count and when and external dll calls FreeLibrary by mistake, the dll does not get unloaded as the ref count is still greater than zero.

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
     HMODULE dllHandle = LoadLibrabry("test.dll");
     // Executing in separate thread
     FreeLibrary(dllHandle);
     return 0;
}

Now we have ensured that if the caller calls FreeLibrary, our dll does not get unloaded as long as the thread is running. We still have one problem unaddressed. Let’s assume that the caller has called FreeLibrary on our dll, before the thread has finished execution. Our thread will still execute properly, since the dll is still loaded (with dll ref count > 0). But when the thread’s job finishes and when it called FreeLibrary on its own dll(at the end of ThreadProc), it could unload our dll from memory because the ref count on our dll could potentially fall to zero. And if there is any instruction from our dll that is yet to be executed (ex. return statements etc.) it would cause an AV.

Sequence of events:

  • External caller loads test.dll using LoadLibrary . Ref count on test.dll is 1.
  • External caller calls AsyncFunction. This spawns a thread to do the async task and returns quickly to the caller.
  • The new thread calls LoadLibrary on test.dll. Ref count now is 2.
  • Caller does not wait for the thread to finish execution and calls FreeLibrary , this reduces the ref count on test.dll to 1 and the loader keeps test.dll loaded.
  • When thread has finished the execution it calls FreeLibrary on test.dll which brings the ref count to 0 and thus leads to dll unload.
  • Any further code execution (return statement or anything else) in test.dll would cause AV.

Instead of calling FreeLibrary at the end of ThreadProc if we call Kernel32’s FreeLibraryAndExitThread it would resolve our issue. All FreeLibraryAndExitThread is doing is calling FreeLibrary on our dll and ExitThread after that. But how does this help, I mean we can also write FreeLibrary and ExitThread at the end of our function, what is the need of calling an API for that??
It is actually a pretty cleaver way to solve this problem, if you think about it. When we call FreeLibraryAndExitThread , the control goes to Kernel32 and our dll gets unloaded from there (and not from within ourselves). After unload, ExitThread is called, this ensures that the control never comes back to our dll for execution (after unload).

 

2 thoughts on “FreeLibraryAndExitThread – Why and when do we need it?”

  1. Thanks for great content. It really helps understand the need for FreeLibraryAndExitThread function. Keep blogging 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *