Windows has a real problem with huge monolithic dlls that inexplicably pull in other huge monolithic dlls. Especially when each dllmain() has its own weird side effects. It leads to bizarre behavior all the time such as this.<p>The weirdest thing that ever happened to me was when Visual Studio 2012 hung in the installer. After debugging with an older VS, it turned out the installer rendered some progress bar with Silverlight, which was hung on audio initialization, which was hung on a file system driver, which was hung on a shitty Apple-provided HFS driver. Uninstalling HFS fixed the installer.<p>Why does an installer even need audio when it never played sound? Because Microsoft dependencies are fucked.
Great post, but it made me sad because of how people limit themselves when it comes to tests.<p>Tests are the things you do after the code works, maybe if you have time. Managers generally only care about hitting a %. Colleagues dodge and avoid them. I don't remember any awards for tests or testers.<p>But tests are so powerful and so cheap...
This reminds me of a desktop heap exhaustion problem IE would regularly trigger for me back in the XP days:<p><a href="https://weblogs.asp.net/kdente/148145" rel="nofollow">https://weblogs.asp.net/kdente/148145</a><p>It all came down to a registry setting that MS neglected to bump up much from the original Win 98 defaults. IIRC the conservative default even persisted into Win 7.<p>That 3MB limit would bring down my 48GB system...
This bug is fixed in the latest insider builds at least.<p>Using the author's own testing tool:<p>With the Spring 2018 release:<p><pre><code> F:\tmp>.\ProcessCreatetests.exe
Main process pid is 46940.
Testing with 1000 descendant processes.
Process creation took 2.309 s (2.309 ms per process).
Lock blocked for 0.003 s total, maximum was 0.000 s.
Average block time was 0.000 s.
Process termination starts now.
Process destruction took 0.656 s (0.656 ms per process).
Lock blocked for 0.001 s total, maximum was 0.000 s.
Average block time was 0.000 s.
Elapsed uptime is 7.08 days.
Awake uptime is 7.08 days.
F:\tmp>.\ProcessCreatetests.exe -user32
Main process pid is 44584.
Testing with 1000 descendant processes with user32.dll loaded.
Process creation took 2.624 s (2.624 ms per process).
Lock blocked for 0.014 s total, maximum was 0.001 s.
Average block time was 0.000 s.
Process termination starts now.
Process destruction took 1.617 s (1.617 ms per process).
Lock blocked for 1.122 s total, maximum was 0.648 s.
Average block time was 0.026 s.
Elapsed uptime is 7.08 days.
Awake uptime is 7.08 days.
</code></pre>
With an insider build:<p><pre><code> C:\tmp>.\ProcessCreatetests.exe
Main process pid is 9928.
Testing with 1000 descendant processes.
Process creation took 2.440 s (2.440 ms per process).
Lock blocked for 0.003 s total, maximum was 0.002 s.
Average block time was 0.000 s.
Process termination starts now.
Process destruction took 1.306 s (1.306 ms per process).
Lock blocked for 0.003 s total, maximum was 0.001 s.
Average block time was 0.000 s.
Elapsed uptime is 4.78 days.
Awake uptime is 3.93 days.
C:\tmp>.\ProcessCreatetests.exe -user32
Main process pid is 14144.
Testing with 1000 descendant processes with user32.dll loaded.
Process creation took 4.756 s (4.756 ms per process).
Lock blocked for 0.022 s total, maximum was 0.004 s.
Average block time was 0.000 s.
Process termination starts now.
Process destruction took 1.823 s (1.823 ms per process).
Lock blocked for 0.003 s total, maximum was 0.001 s.
Average block time was 0.000 s.
Elapsed uptime is 4.78 days.
Awake uptime is 3.93 days.
</code></pre>
There's no longer a difference in lock blocked time whether or not you load user32 during process destruction. Nor does the very obvious mouse stuttering still happen.
Unless the compiler can <i>prove</i> you're never going to run into that case, it can't remove the call, and because the call is an imported function it still has to create the import and have an entry in the IAT for it, so it needs to be resolved at load time. Not all that surprising IMHO.
wow, how come the mere presence of a function causes a DLL to get loaded? Is it because in order to compile, the DLL (or its export definition) needs to be present, and the compiler does some magic because of that?
> "The first fix was to avoid calling CommandLineToArgvW by manually parsing the command-line."<p>> "The second fix was to delay load shell32.dll."<p>If your build pipeline is continuously spawning processes all-over, to the point "delay loading" makes a significant difference - it's time to start re-evaluating the entire pipeline and the practices employed.