{"id":17543,"date":"2009-07-10T10:00:00","date_gmt":"2009-07-10T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2009\/07\/10\/if-dynamic-dll-dependencies-were-tracked-theyd-be-all-backwards\/"},"modified":"2009-07-10T10:00:00","modified_gmt":"2009-07-10T10:00:00","slug":"if-dynamic-dll-dependencies-were-tracked-theyd-be-all-backwards","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20090710-00\/?p=17543","title":{"rendered":"If dynamic DLL dependencies were tracked, they&#039;d be all backwards"},"content":{"rendered":"<p>Whenever the issue of DLL dependencies arises, I can count on somebody arguing that <a href=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/06\/09\/8582411.aspx#8588111\"> these dynamic dependencies should be tracked, even if doing so cannot be proven to be reliable<\/a>. Even if one could walk the call stack reliably, you would <i>still<\/i> get it wrong.\n The example I gave originally was the common helper library, where <code>A.DLL<\/code> loads <code>B.DLL<\/code> via an intermediate function in <code>MIDDLE.DLL<\/code>. You want the dependency to be that <code>A.DLL<\/code> depends on <code>B.DLL<\/code>, but instead the dependency gets assigned to <code>MIDDLE.DLL<\/code>.\n &#8220;But so what? Instead of a direct dependency from <code>A.DLL<\/code> to <code>B.DLL<\/code>, we just have two dependencies, one from <code>A.DLL<\/code> to <code>MIDDLE.DLL<\/code>, and another from <code>MIDDLE.DLL<\/code> to <code>B.DLL<\/code>. It all comes out to the same thing in the end.&#8221;\n Actually, it doesn&#8217;t. It comes out much worse.\n After all, <code>MIDDLE.DLL<\/code> is your common helper library. All of the DLLs in your project depend on it. Therefore, the dependency diagram in reality looks like this:<\/p>\n<table border=\"0\">\n<tr>\n<td><code>A.DLL<\/code><\/td>\n<td>&rarr;<\/td>\n<td><code>B.DLL<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td>&#8600;<\/td>\n<td>&darr;<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td colspan=\"2\"><code>MIDDLE.DLL<\/code><\/td>\n<\/tr>\n<\/table>\n<p> <code>A.DLL<\/code> depends on <code>B.DLL<\/code>, and both DLLs depend on <code>MIDDLE.DLL<\/code>. That common DLL really should be called <code>BOTTOM.DLL<\/code> since everybody depends on it.\n Now you can see why the dependency chain <code>A.DLL &rarr; MIDDLE.DLL &rarr; B.DLL<\/code> is horribly wrong. Under the incorrect dependency chain, the DLLs would be uninitialized in the order <code>A.DLL<\/code>, <code>MIDDLE.DLL<\/code>, <code>B.DLL<\/code>, even though <code>B.DLL<\/code> depends on <code>MIDDLE.DLL<\/code>. That&#8217;s because your &#8220;invented&#8221; dependency <i>introduces a cycle in the dependency chain<\/i>, and a bogus one at that. Once you have cycles in the dependency chain, everything falls apart. You took something that might have worked into something that explodes upon impact.\n This situation appears much more often than you think. In fact it happens <i>all the time<\/i>. Because in real life, the loader is implemented in the internal library <code>NTDLL.DLL<\/code>, and <code>KERNEL32.DLL<\/code> is just a wrapper function around the real DLL loader. In other words, if your <code>A.DLL<\/code> calls <code>LoadLibrary(\"B.DLL\")<\/code>, you are already using a middle DLL; its name is <code>KERNEL32.DLL<\/code>. If this &#8220;dynamic dependency generation&#8221; were followed, then <code>KERNEL32.DLL<\/code> would be listed as <i>dependent on everything<\/i>. When it came time to uninitialize, <code>KERNEL32.DLL<\/code> would uninitialized before all dynamically-loaded DLLs, because it was the one who loaded them, and then all the dynamically-loaded DLLs would find themselves in an interesting world where <code>KERNEL32.DLL<\/code> no longer existed.\n Besides, the original problem arises when <code>A.DLL<\/code> calls a function in <code>B.DLL<\/code> during its <code>DLL_PROCESS_DETACH<\/code> handler, going against the rule that you shouldn&#8217;t call anything outside your DLL from your <code>DllMain<\/code> function (except perhaps a little bit of <code>KERNEL32<\/code> but even then, it&#8217;s still not the best idea). It&#8217;s one thing to make accommodations so that existing bad programs continue to run, but it&#8217;s another to build an entire infrastructure built on unreliable heuristics in order to encourage people to do something they shouldn&#8217;t be doing in the first place, and whose guesses end up taking a working situation and breaking it.<\/p>\n<p> You can&#8217;t even write programs to take advantage of this new behavior because walking the stack is itself unreliable. You recompile your program with different optimizations, and all of a sudden the stack walking stops working because you enabled tail call elimination. If somebody told you, &#8220;Hey, we added this feature that isn&#8217;t reliable,&#8221; I suspect your reaction would not be &#8220;Awesome, let me start depending on it!&#8221; <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Whenever the issue of DLL dependencies arises, I can count on somebody arguing that these dynamic dependencies should be tracked, even if doing so cannot be proven to be reliable. Even if one could walk the call stack reliably, you would still get it wrong. The example I gave originally was the common helper library, [&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-17543","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Whenever the issue of DLL dependencies arises, I can count on somebody arguing that these dynamic dependencies should be tracked, even if doing so cannot be proven to be reliable. Even if one could walk the call stack reliably, you would still get it wrong. The example I gave originally was the common helper library, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17543","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=17543"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17543\/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=17543"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=17543"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=17543"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}