{"id":15253,"date":"2010-01-15T07:00:00","date_gmt":"2010-01-15T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/01\/15\/how-you-might-be-loading-a-dll-during-dll_process_detach-without-even-realizing-it\/"},"modified":"2010-01-15T07:00:00","modified_gmt":"2010-01-15T07:00:00","slug":"how-you-might-be-loading-a-dll-during-dll_process_detach-without-even-realizing-it","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100115-00\/?p=15253","title":{"rendered":"How you might be loading a DLL during DLL_PROCESS_DETACH without even realizing it"},"content":{"rendered":"<p>\nAs you are I&#8217;m sure aware,\nyou shouldn&#8217;t be doing much of anything in your <code>DllMain<\/code>\nfunction,\nbut you have to watch out for cases where you end up doing them\naccidentally.\n<\/p>\n<p>\nSome time ago, I was investigating a failure which was traced back\nto loading a DLL inside <code>DLL_PROCESS_DETACH<\/code>.\nWait, what kind of insane person <i>loads<\/i> a DLL as part of\nshutting down?\nShouldn&#8217;t you be cleaning up stuff, not creating new stuff?\n<\/p>\n<p>\nThe following is not the actual code, but it captures the same\nspirit:\n<\/p>\n<pre>\nINFO *CachedInfo;\nBOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, void *pvReserved)\n{\n  switch (dwReason) {\n  ...\n  case DLL_PROCESS_DETACH:\n    ...\n    CoTaskMemFree(CachedInfo);\n    ...\n  }\n  return TRUE;\n}\n<\/pre>\n<p>\nThere is some global variable that contains a pointer to memory\nthat was allocated by <code>CoTaskMemAlloc<\/code>.\nIn this case, I made it a cache, but the details aren&#8217;t important.\nWhen the DLL is detached from the process, we free the cached memory\nso we don&#8217;t have a leak.\nSince it is okay to pass <code>NULL<\/code> to\nthe <code>CoTaskMemFree<\/code> function (it simply returns\nwithout doing anything),\nthe cleanup code works even if we never called a function that\nput a value into the cache.\n<\/p>\n<p>\nExcept that this code ended up loading a DLL.\nThe reason is delay-loading.\n<\/p>\n<p>\nThe authors of this DLL sped up its load time by marking\n<code>OLEAUT32.DLL<\/code> as a\n<a HREF=\"http:\/\/msdn.microsoft.com\/yx9zd12s.aspx\">\ndelay-loaded DLL<\/a>,\nwhich means that it doesn&#8217;t get loaded until somebody calls a\nfunction in it.\n<\/p>\n<p>\nAnd in fact, nobody called a function from <code>OLEAUT32<\/code>.\nEver.\n<\/p>\n<p>\n&#8220;Hooray!&#8221; you shout.\n&#8220;We avoided loading <code>OLEAUT32<\/code> altogether.&#8221;\nAfter all, the fastest code is code that doesn&#8217;t run.\n<\/p>\n<p>\nExcept that it does run.\nRight there.\nIn your <code>DLL_PROCESS_DETACH<\/code> handler.\n<\/p>\n<p>\nSince nobody called a function from <code>OLEAUT32<\/code>,\nthe call to <code>CoTaskMemFree<\/code> was the first call to\n<code>OLEAUT32<\/code> and therefore\n<i>caused it to be loaded<\/i>.\nFrom inside a <code>DLL_PROCESS_DETACH<\/code> handler.\n<\/p>\n<p>\nDelay-loading is one of those features that is very convenient\nand saves you a lot of typing (namely, writing those stub functions\nyourself),\nbut you also have to understand what&#8217;s going on so you don&#8217;t\nuse it incorrectly.\n(In this case, a superficially-redundant\n<code>if (CachedInfo != NULL)<\/code> test needs to be inserted.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As you are I&#8217;m sure aware, you shouldn&#8217;t be doing much of anything in your DllMain function, but you have to watch out for cases where you end up doing them accidentally. Some time ago, I was investigating a failure which was traced back to loading a DLL inside DLL_PROCESS_DETACH. Wait, what kind of insane [&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-15253","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>As you are I&#8217;m sure aware, you shouldn&#8217;t be doing much of anything in your DllMain function, but you have to watch out for cases where you end up doing them accidentally. Some time ago, I was investigating a failure which was traced back to loading a DLL inside DLL_PROCESS_DETACH. Wait, what kind of insane [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/15253","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=15253"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/15253\/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=15253"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=15253"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=15253"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}