{"id":94415,"date":"2016-09-29T07:00:00","date_gmt":"2016-09-29T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=94415"},"modified":"2019-03-13T11:07:21","modified_gmt":"2019-03-13T18:07:21","slug":"20160929-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160929-00\/?p=94415","title":{"rendered":"The lackey catastrophe"},"content":{"rendered":"<p>We encountered a real problem with global object destruction in Explorer. The object in question was an RAII container for a graphics object, so its destructor destroyed the graphics object. But the call to destroy the object was crashing. <\/p>\n<pre>\nGDI32!IS_INDEX_IN_USER_SHARED_ARRAY+0x17\nGDI32!HANDLE_TO_INDEX+0x1a\nGDI32!DeleteObject+0x2a\nexplorer!CBitmap::~CBitmap+0x20\nmsvcrt!doexit+0xb6\nmsvcrt!_cexit+0xb\nmsvcrt!__CRTDLL_INIT+0x9f\nntdll!LdrxCallInitRoutine+0x16\nntdll!LdrpCallInitRoutine+0x43\nntdll!LdrShutdownProcess+0x1c1\nntdll!RtlExitUserProcess+0x96\nkernel32!ExitProcess+0x32\nexplorer!wWinMain+0x4ef\nexplorer!WinMainCRTStartup+0x151\nKERNEL32!BaseThreadInitThunk+0x24\nntdll!__RtlUserThreadStart+0x2b\nntdll!_RtlUserThreadStart+0x1b\n<\/pre>\n<p>What&#8217;s going on? <\/p>\n<p>The call to <code>Delete&shy;Object<\/code> was occurring after <code>GDI32<\/code> had already run its <strike><code>DLL_PROCESS_ATTACH<\/code><\/strike> <code>DLL_PROCESS_DETACH<\/code>. As a result, it was calling into a DLL that had already uninitialized, so bad things happen. <\/p>\n<p>But wait, how can you call into a DLL that has already uninitialized? The EXE links to the DLL via a load-time dependency, so the EXE should uninitialize first. But it&#8217;s not. Why not? <\/p>\n<p>Recall <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20141017-00\/?p=43823\">how global objects are constructed and destructed<\/a>. If the global object had been in a DLL, then indeed the loader dependency analysis would have seen that the global object&#8217;s DLL depends upon <code>GDI32<\/code>. <\/p>\n<p>As we saw in the earlier discussion, executables do not have <code>DLL_PROCESS_DETACH<\/code>. You can look at the situation in two ways: One interpretation is that the executable has already stopped running at the point it calls <code>Exit&shy;Process<\/code>. All that&#8217;s left is to shut down the DLLs. Another interpretation is that the executable is <i>always<\/i> running (seeing as DLLs run in the context of a process), so there&#8217;s no point trying to wait until the executable has &#8220;finished&#8221; because if you did that, you&#8217;d be waiting forever. <\/p>\n<p>Anyway, regardless of how you choose to look at the situation, the problem is the same: The lackey we hired to run down our global objects is running them down too late. <\/p>\n<p>This is a case where the C runtime is doing the best it possibly can, but it&#8217;s still not good enough. <\/p>\n<p>Next time, we&#8217;ll look at one possible extrication from this quandary. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>You know it will be done, but you don&#8217;t know when.<\/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-94415","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You know it will be done, but you don&#8217;t know when.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94415","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=94415"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94415\/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=94415"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=94415"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=94415"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}