{"id":40853,"date":"2004-01-28T07:00:00","date_gmt":"2004-01-28T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/01\/28\/another-reason-not-to-do-anything-scary-in-your-dllmain-inadvertent-deadlock\/"},"modified":"2004-01-28T07:00:00","modified_gmt":"2004-01-28T07:00:00","slug":"another-reason-not-to-do-anything-scary-in-your-dllmain-inadvertent-deadlock","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040128-00\/?p=40853","title":{"rendered":"Another reason not to do anything scary in your DllMain: Inadvertent deadlock"},"content":{"rendered":"<p>\nYour DllMain function runs inside the loader lock,\none of the few times the OS lets you run code while one\nof its internal locks is held.\nThis means that you must be extra careful not to violate\na lock hierarchy in your DllMain; otherwise, you\nare asking for a deadlock.\n<\/p>\n<p>\n(You do have a\n<a HREF=\"http:\/\/www.osr.com\/ddk\/ddtools\/dv_8pkj.htm\">\nlock hierarchy<\/a> in your DLL, right?)\n<\/p>\n<p>\nThe loader lock is taken by any function that needs to\naccess the list of DLLs loaded into the process.\nThis includes functions like GetModuleHandle\nand GetModuleFileName.\nIf your DllMain enters a critical section or waits on\na synchronization object, and that critical section or\nsynchronization object is owned by some code that is\nin turn waiting for the loader lock, you just created a deadlock:\n<\/p>\n<pre>\n\/\/ global variable\nCRITICAL_SECTION g_csGlobal;\n\/\/ some code somewhere\nEnterCriticalSection(&amp;g_csGlobal);\n... GetModuleFileName(MyInstance, ..);\nLeaveCriticalSection(&amp;g_csGlobal);\nBOOL WINAPI\nDllMain(HINSTANCE hinstDLL, DWORD fdwReason,\n        LPVOID lpvReserved)\n{\n  switch (fdwReason) {\n  ...\n  case DLL_THREAD_DETACH:\n   EnterCriticalSection(&amp;g_csGlobal);\n   ...\n  }\n  ...\n}\n<\/pre>\n<p>\nNow imagine that some thread is happily executing the first\ncode fragment and enters g_csGlobal, then\ngets pre-empty.  During this time, another thread exits.\nThis enters the loader lock and sends out\nDLL_THREAD_DETACH messages while the loader lock is still held.\n<\/p>\n<p>\nYou receive the DLL_THREAD_DETACH and attempt to enter your DLL&#8217;s\ng_csGlobal.  This blocks on the first thread, who owns the\ncritical section. That thread then resumes execution and calls\nGetModuleFileName. This function requires the loader lock\n(since it&#8217;s accessing the list of DLLs loaded into the process),\nso it blocks, since the loader lock is owned by somebody else.\n<\/p>\n<p>\nNow you have a deadlock:<\/p>\n<ul>\n<li>\ng_cs owned by first thread, waiting on loader lock.<\/p>\n<li>\nLoader lock owned by second thread, waiting on g_cs.\n<\/ul>\n<p>\nI have seen this happen. It&#8217;s not pretty.\n<\/p>\n<p>Moral of the story: Respect the loader lock.\nInclude it in your lock hierarchy rules if you take\nany locks in your DllMain.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Your DllMain function runs inside the loader lock, one of the few times the OS lets you run code while one of its internal locks is held. This means that you must be extra careful not to violate a lock hierarchy in your DllMain; otherwise, you are asking for a deadlock. (You do have a [&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-40853","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Your DllMain function runs inside the loader lock, one of the few times the OS lets you run code while one of its internal locks is held. This means that you must be extra careful not to violate a lock hierarchy in your DllMain; otherwise, you are asking for a deadlock. (You do have a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40853","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=40853"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40853\/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=40853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=40853"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=40853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}