A technical blog post by Raymond Chen investigating a memory corruption bug where a single byte 0x01 corrupts HMODULE handles, causing DLLs to be improperly freed and leading to crashes at process termination.
<p>Last time, <a title="The case of the DLL that was not present in memory despite not being formally unloaded" href="https://devblogs.microsoft.com/oldnewthing/20260625-00/?p=112467"> we looked at crashes caused by a DLL being removed from memory behind everybody’s back</a>, causing crashes when somebody tried to call into that no-longer-there DLL that everybody thought was still there.</p>
<p>A colleague of mine who was looking at other crashes coming from this process found that most of those other crashes were also of the form “a data structure was corrupted because somebody wrote the single byte <tt>01</tt> into it.” That piece of information made everything fall into place for my side of the investigation.</p>
<p>We saw earlier that <a title="What does it mean when the bottom bit of my HMODULE is set?" href="https://devblogs.microsoft.com/oldnewthing/20260619-00/?p=112447"> the bottom bit of the <code>HMODULE</code> is set for datafile module handles</a>. Therefore, if one of these stray <tt>01</tt> bytes happens to overwrite the bottom byte of an existing <code>HMODULE</code> handle, that turns it into a (fake) datafile module handle. And then, during process destruction, a component dutifully cleans up the DLLs they loaded by freeing them (say because they were stored in an RAII type like <code>wil::<wbr />unique_<wbr />hmodule</code>), the code will pass this (fake) datafile module handle to <code>FreeLibrary</code>. The <code>FreeLibrary</code> function sees the bottom bit set and says, “Oh, this must be the handle to a module that was loaded via <code>LOAD_<wbr />LIBRARY_<wbr />AS_<wbr />DATAFILE</code>,” so it frees it as a datafile.</p>
<p>Freeing a datafile module means undoing the steps that were taken when the module was loaded as a datafile: Unmapping the DLL from memory. In particular, loading a module as a datafile does not add the DLL to the list of DLLs that were loaded as code; therefore, unloading a datafile module doesn’t remove it from that list. As far as the DLL list is concerned, the DLL is still in memory.</p>
<p>A one-bit error caused the code to lie and attempt to free a module handle that did not correspond to a <code>LoadLibrary</code> call, resulting in mass havoc.</p>
<p>The “DLL unmapped from memory” crash is just an alternate manifestation of the “somebody is writing <tt>01</tt> bytes to places they shouldn’t” bug. The original bug had a larger <a title="Microspeak: Bucket bugs, bucket spray, bug spray, and failure shift" href="https://devblogs.microsoft.com/oldnewthing/20200121-00/?p=103351"> bucket spray</a> than we initially thought.</p>
<p>The good news is that all of the crashes have funneled down to a single bug. The bad news is that you now have to debug this one memory corruption bug.</p>
<p>Unfortunately, at the time of this writing, the root memory corruption bug in the third party program has yet to be identified. We don’t know whether it’s coming from an operating system component or from the program itself. Though the fact that it appears to occur only in one process, where it sprays across multiple modules, suggests that it’s a problem with that program, or that there’s something peculiar about how this specific process uses the system.</p>
<p>If you look at the original stack trace, you can see that the problem is occurring at process termination. That’s probably why the problem has lurked for so long: Crashes at exit often go unnoticed because there is no end-user loss of functionality. The user was finished with the program anyway. Whether it exits cleanly or with a crash doesn’t affect the user much.</p>
<p>Sorry. Not all stories have a happy ending.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260626-00/?p=112472">The case of the DLL that was not present in memory despite not being formally unloaded, part 2</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
# The case of the DLL that was not present in memory despite not being formally unloaded, part 2 - The Old New Thing
Source: [https://devblogs.microsoft.com/oldnewthing/20260626-00?p=112472](https://devblogs.microsoft.com/oldnewthing/20260626-00?p=112472)
Last time,[we looked at crashes caused by a DLL being removed from memory behind everybody’s back](https://devblogs.microsoft.com/oldnewthing/20260625-00/?p=112467), causing crashes when somebody tried to call into that no\-longer\-there DLL that everybody thought was still there\.
A colleague of mine who was looking at other crashes coming from this process found that most of those other crashes were also of the form “a data structure was corrupted because somebody wrote the single byte01into it\.” That piece of information made everything fall into place for my side of the investigation\.
We saw earlier that[the bottom bit of the`HMODULE`is set for datafile module handles](https://devblogs.microsoft.com/oldnewthing/20260619-00/?p=112447)\. Therefore, if one of these stray01bytes happens to overwrite the bottom byte of an existing`HMODULE`handle, that turns it into a \(fake\) datafile module handle\. And then, during process destruction, a component dutifully cleans up the DLLs they loaded by freeing them \(say because they were stored in an RAII type like`wil::unique\_hmodule`\), the code will pass this \(fake\) datafile module handle to`FreeLibrary`\. The`FreeLibrary`function sees the bottom bit set and says, “Oh, this must be the handle to a module that was loaded via`LOAD\_LIBRARY\_AS\_DATAFILE`,” so it frees it as a datafile\.
Freeing a datafile module means undoing the steps that were taken when the module was loaded as a datafile: Unmapping the DLL from memory\. In particular, loading a module as a datafile does not add the DLL to the list of DLLs that were loaded as code; therefore, unloading a datafile module doesn’t remove it from that list\. As far as the DLL list is concerned, the DLL is still in memory\.
A one\-bit error caused the code to lie and attempt to free a module handle that did not correspond to a`LoadLibrary`call, resulting in mass havoc\.
The “DLL unmapped from memory” crash is just an alternate manifestation of the “somebody is writing01bytes to places they shouldn’t” bug\. The original bug had a larger[bucket spray](https://devblogs.microsoft.com/oldnewthing/20200121-00/?p=103351)than we initially thought\.
The good news is that all of the crashes have funneled down to a single bug\. The bad news is that you now have to debug this one memory corruption bug\.
Unfortunately, at the time of this writing, the root memory corruption bug in the third party program has yet to be identified\. We don’t know whether it’s coming from an operating system component or from the program itself\. Though the fact that it appears to occur only in one process, where it sprays across multiple modules, suggests that it’s a problem with that program, or that there’s something peculiar about how this specific process uses the system\.
If you look at the original stack trace, you can see that the problem is occurring at process termination\. That’s probably why the problem has lurked for so long: Crashes at exit often go unnoticed because there is no end\-user loss of functionality\. The user was finished with the program anyway\. Whether it exits cleanly or with a crash doesn’t affect the user much\.
Sorry\. Not all stories have a happy ending\.
### Category
### Topics
## Author

Raymond has been involved in the evolution of Windows for more than 30 years\. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie\-jeebies\. The Web site spawned a book, coincidentally also titled The Old New Thing \(Addison Wesley 2007\)\. He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information\.
This article investigates a crash dump where a stack overflow caused repeated exception handling loops in shell32.dll during process shutdown. The analysis traces the recursive exception handling and identifies the root cause involving DLL unloading.
This article explains that the Windows loader sets the bottom bit of an HMODULE handle to indicate the DLL was loaded as a data file (LOAD_LIBRARY_AS_DATAFILE), affecting resource lookup and freeing behavior without adding it to the module list.
QuestDB engineers debug a sporadic Windows hang caused by a deadlock involving the Windows DLL Loader Lock, Rust thread-local storage destruction, JNI detach, and JVM garbage collection safepoint mechanics.
This video uses disassembly and the WinDbg debugging tool to reveal that the eight mystery bytes that appear when calloc allocates memory in an x86 environment are actually the entry header of the Windows heap manager, containing information such as the current block size and the previous block size.