{"id":2733,"date":"2013-11-05T07:00:00","date_gmt":"2013-11-05T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/11\/05\/what-is-the-point-of-freelibraryandexitthread\/"},"modified":"2013-11-05T07:00:00","modified_gmt":"2013-11-05T07:00:00","slug":"what-is-the-point-of-freelibraryandexitthread","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20131105-00\/?p=2733","title":{"rendered":"What is the point of FreeLibraryAndExitThread?"},"content":{"rendered":"<p>\nThe <code>Free&shy;Library&shy;And&shy;Exit&shy;Thread<\/code>\nfunction seems pointless.\nI mean, all the function does is\n<\/p>\n<pre>\nDECLSPEC_NORETURN\nvoid WINAPI FreeLibraryAndExitThread(\n    HMODULE hLibModule,\n    DWORD dwExitCode)\n{\n    FreeLibrary(hLibModule);\n    ExitThread(dwExitCode);\n}\n<\/pre>\n<p>\nWho needs such a trivial function?\nIf I wanted to do that, I could just write it myself.\n<\/p>\n<pre>\nDWORD CALLBACK MyThreadProc(void *lpParameter)\n{\n    ... blah blah blah ...\n    \/\/ <strike STYLE=\"color: red\">FreeLibraryAndExitThread(g_hinstSelf, 0);<\/strike>\n    <font COLOR=\"blue\">FreeLibrary(g_hinstSelf);\n    ExitThread(0);<\/font>\n}\n<\/pre>\n<p>\nAnd then you discover that occasionally your program crashes.\nWhat&#8217;s going on?\n<\/p>\n<p>\nLet&#8217;s rewind and look at the original problem.\n<\/p>\n<p>\nOriginally, you had code that did something like this:\n<\/p>\n<pre>\nDWORD CALLBACK SomethingThreadProc(void *lpParameter)\n{\n ... do something ...\n return 0;\n}\nvoid DoSomethingInTheBackground()\n{\n DWORD dwThreadId;\n HANDLE hThread = CreateThread(nullptr, 0, SomethingThreadProc,\n                  nullptr, 0, &amp;dwThreadId);\n if (hThread) CloseHandle(hThread);\n}\n<\/pre>\n<p>\nThis worked great, until somebody did this to your DLL:\n<\/p>\n<pre>\nHMODULE hmodDll = LoadLibrary(TEXT(\"awesome.dll\"));\nif (hmodDll) {\n auto pfn = reinterpret_cast&lt;decltype(DoSomethingInTheBackground)*&gt;\n            (GetProcAddress(hmodDll, \"DoSomethingInTheBackground\"));\n if (pfn) pfn();\n FreeLibrary(hmodDll);\n}\n<\/pre>\n<p>\nThis code fragment calls your\n<code>Do&shy;Something&shy;In&shy;The&shy;Background<\/code>\nfunction and then immediately unloads the DLL,\npresumably because all they wanted to do was call that one function.\n<\/p>\n<p>\nNow you have a problem:\nThat\n<code>Free&shy;Library<\/code>\ncall frees your DLL,\nwhile your\n<code>Something&shy;Thread&shy;Proc<\/code> is still running!\nResult:\nA crash at an address where there is no code.\nOlder debuggers reported this as a crash in &lang;unknown&rang;;\nnewer ones can dig into the recently-unloaded modules list\nand report it as a crash in\n<code>awesome_unloaded<\/code>.\n<\/p>\n<p>\nThis is a very common class of error.\nWhen I helped out the application compatibility team\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/06\/02\/10018606.aspx\">\nby looking at crashes in third-party code<\/a>,\nthe majority of the crashes I looked at in Internet Explorer\nwere of this sort,\nwhere a plug-in got unloaded while it still had a running thread.\n<\/p>\n<p>\nHow do you prevent your DLL from being unloaded while you still\nhave code running (or have registered callbacks)?\nYou perform a bonus <code>Load&shy;Library<\/code> on yourself,\nthereby bumping your DLL reference count by one.\n<\/p>\n<p>\nIf you don&#8217;t need to support Windows&nbsp;2000,\nyou can use the new <code>Get&shy;Module&shy;Handle&shy;Ex<\/code> function,\nwhich is much more convenient and probably a lot faster, too.\n<\/p>\n<pre>\nBOOL IncrementDLLReferenceCount(HINSTANCE hinst)\n{\n HMODULE hmod;\n return GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,\n                          reinterpret_cast&lt;LPCTSTR&gt;(hinst),\n                          &amp;hmod);\n}\n<\/pre>\n<p>\nBumping the DLL reference count means that when the original person\nwho called <code>Load&shy;Library<\/code> finally calls\n<code>Free&shy;Library<\/code>,\nyour DLL will still remain in memory because the reference count\nhas not yet dropped all the way to zero because you have taken\na reference to the DLL yourself.\n<\/p>\n<p>\nWhen you unregister your callback or your background thread finishes,\nyou call\n<code>Free&shy;Library<\/code> to release your reference to the DLL,\nand if that&#8217;s the last reference, then the DLL will be unloaded.\n<\/p>\n<p>\nBut wait, now we have a problem.\nWhen you call\n<code>Free&shy;Library<\/code> to release your reference to the DLL,\nthat call might end up unloading the code that is making the call.\nWhen the call returns, there is no more code there.\nThis most commonly happens when you are calling\n<code>Free&shy;Library<\/code> on yourself and that was the last reference.\nIn rarer circumstances, it happens indirectly through a\nchain of final references.\n<\/p>\n<p>\nLet&#8217;s walk through that scenario again, since understanding it is central\nto solving the problem.\n<\/p>\n<ol>\n<li>Some application calls <code>Load&shy;Library<\/code> on your DLL.\n    The reference count on your DLL is now 1.<\/p>\n<li>The application calls a function in your DLL that uses a background\n    thread.<\/p>\n<li>Your DLL prepares for the background thread by doing a\n    <code>Get&shy;Module&shy;Handle&shy;Ex<\/code> on itself,\n    to avoid a premature unload.\n    The reference count on your DLL is now 2.<\/p>\n<li>Your DLL starts the background thread.\n<li>The application decides that it doesn&#8217;t need your DLL any more,\n    so it calls <code>Free&shy;Library<\/code>.\n    The reference count on your DLL is now 1.<\/p>\n<li>Your DLL background thread finishes its main work.\n    The thread procedure ends with the lines<\/p>\n<pre>\n    FreeLibrary(g_hinstSelf);\n    return 0;\n<\/pre>\n<li>The thread procedure calls\n    <code>Free&shy;Library(g_hinst&shy;Self)<\/code>\n    to drop its reference count.<\/p>\n<li>The\n    <code>Free&shy;Library<\/code> function frees your DLL.<\/p>\n<li>The\n    <code>Free&shy;Library<\/code> function returns to its caller,\n    namely your thread procedure.<\/p>\n<li>Crash, because your thread procedure was unloaded!\n<\/ol>\n<p>\nThis is why you need\n<code>Free&shy;Library&shy;And&shy;Exit&shy;Thread<\/code>:\nSo that the return address of the <code>Free&shy;Library<\/code>\nis not in code that&#8217;s being unloaded by the\n<code>Free&shy;Library<\/code> itself.\n<\/p>\n<p>\nChange the last two lines of the thread procedure to\n<code>Free&shy;Library&shy;AndExit&shy;Thread(g_hinstSelf, 0);<\/code>\nand watch what happens.\nThe first five steps are the same, and then we take a turn:\n<\/p>\n<ol START=\"6\">\n<li>Your DLL background thread finishes its main work.\n    The thread procedure ends with a call to<\/p>\n<pre>\n    FreeLibraryAndExitThread(g_hinstSelf, 0);\n<\/pre>\n<li>The\n    <code>Free&shy;Library&shy;And&shy;Exit&shy;Thread<\/code>\n    function calls\n    <code>Free&shy;Library(g_hinst&shy;Self)<\/code>.<\/p>\n<li>The\n    <code>Free&shy;Library<\/code> function frees your DLL.<\/p>\n<li>The\n    <code>Free&shy;Library<\/code> function returns to its caller,\n    which is not your thread procedure but rather the\n    <code>Free&shy;Library&shy;And&shy;Exit&shy;Thread<\/code>\n    function,\n    which was not unloaded.<\/p>\n<li>The\n    <code>Free&shy;Library&shy;And&shy;Exit&shy;Thread<\/code>\n    function calls <code>Exit&shy;Thread(0)<\/code>.<\/p>\n<li>The thread exits and no further code is executed.\n<\/ol>\n<p>\nThat&#8217;s why the\n<code>Free&shy;Library&shy;And&shy;Exit&shy;Thread<\/code>\nfunction exists:\nSo you don&#8217;t pull the rug out from underneath yourself.\nInstead, you have somebody else pull the rug for you.\n<\/p>\n<p>\nThis issue of keeping your DLL from unloading prematurely\nrears its head in several ways.\nWe&#8217;ll look at some of them in the next few days.\n<\/p>\n<p>\n<b>Bonus chatter<\/b>:\nThe thread pool version of\n<code>Free&shy;Library&shy;And&shy;Exit&shy;Thread<\/code>\nis\n<code>Free&shy;Library&shy;When&shy;Callback&shy;Returns<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Free&shy;Library&shy;And&shy;Exit&shy;Thread function seems pointless. I mean, all the function does is DECLSPEC_NORETURN void WINAPI FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode) { FreeLibrary(hLibModule); ExitThread(dwExitCode); } Who needs such a trivial function? If I wanted to do that, I could just write it myself. DWORD CALLBACK MyThreadProc(void *lpParameter) { &#8230; blah blah blah &#8230; \/\/ FreeLibraryAndExitThread(g_hinstSelf, 0); [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-2733","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The Free&shy;Library&shy;And&shy;Exit&shy;Thread function seems pointless. I mean, all the function does is DECLSPEC_NORETURN void WINAPI FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode) { FreeLibrary(hLibModule); ExitThread(dwExitCode); } Who needs such a trivial function? If I wanted to do that, I could just write it myself. DWORD CALLBACK MyThreadProc(void *lpParameter) { &#8230; blah blah blah &#8230; \/\/ FreeLibraryAndExitThread(g_hinstSelf, 0); [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2733","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=2733"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2733\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=2733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=2733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=2733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}