{"id":111781,"date":"2025-11-11T07:00:00","date_gmt":"2025-11-11T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111781"},"modified":"2025-11-10T06:23:42","modified_gmt":"2025-11-10T14:23:42","slug":"20251111-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20251111-00\/?p=111781","title":{"rendered":"Behind the scenes on how Windows 95 application compatibility patched broken programs"},"content":{"rendered":"<p>Whenever possible, Windows 95 made application compatibility tweaks through things like compatibility flags that alter the behavior of the system for any program the flag was applied to. Using compatibility flags allows the fix to be generalized: If one program has a problem, there&#8217;s a good chance that another program will also have that same problem. So you can apply the flag to the second program and take advantage of the same fix.<\/p>\n<p>On very rare occasions, the problem is too deeply embedded in the program, and the only reasonable option is to patch it. Out of safety, the Windows 95 team got written permission from the vendor whenever they needed to patch a program. The consultation included detailed information on what the problem was and how it was going to be patched. In exchange, the team requested information from the vendor on what versions of their product are affected (and if they could send those versions for analysis), as well as a promise to fix the problem in their next version, because the next version won&#8217;t have the benefit of the patch.<\/p>\n<p>The patches themselves were kept in the registry under <tt>HKLM\\<wbr \/>System\\<wbr \/>CurrentControlSet\\<wbr \/>Control\\<wbr \/>SessionManager\\<wbr \/>AppPatches\\<wbr \/>\u2329ModuleName\u232a\\<wbr \/>\u2329Detection string\u232a<\/tt>. When a 16-bit module is loaded and its target Windows version is less than 4.0, the kernel looks through all the detection strings and tries them one by one to see if any of them triggers.<\/p>\n<p>The detection string is decoded into bytes. The first byte represents the match algorithm, and the rest are parameters to the algorithm.<\/p>\n<p>Type <tt>01<\/tt>: Matching the NE header using 8-bit offsets. The value <tt>of<\/tt> is the 8-bit offset into the header, and the <tt>xx<\/tt> values are the bytes to match.<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>01<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>of<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<td style=\"text-align: left;\"><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none;\"><tt>nn<\/tt> bytes<\/td>\n<td style=\"text-align: left;\">Terminator<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2&quot;\">Repeat as needed<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>02<\/tt>: Matching the NE header using 16-bit offsets. The value <tt>offs<\/tt> is the 16-bit offset (little-endian) into the header, and the <tt>xx<\/tt> values are the bytes to match.<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>02<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>of<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>fs<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<td style=\"text-align: left;\"><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none;\"><tt>nn<\/tt> bytes<\/td>\n<td style=\"text-align: left;\">Terminator<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2&quot;\">Repeat as needed<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>03<\/tt>: Matching the file contents using 16-bit offsets. The value <tt>offs<\/tt> is the 16-bit offset (little-endian) into the file, and the <tt>xx<\/tt> values are the bytes to match.<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>03<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>of<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>fs<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<td style=\"text-align: left;\"><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none;\"><tt>nn<\/tt> bytes<\/td>\n<td style=\"text-align: left;\">Terminator<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2&quot;\">Repeat as needed<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>04<\/tt>: Matching the file contents using 24-bit offsets. The value <tt>offset<\/tt> is the 24-bit offset (little-endian) into the file, and the <tt>xx<\/tt> values are the bytes to match.<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>04<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>of<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>fs<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>et<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<td style=\"text-align: left;\"><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none;\"><tt>nn<\/tt> bytes<\/td>\n<td style=\"text-align: left;\">Terminator<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2&quot;\">Repeat as needed<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>05<\/tt>: Matching the file contents using 32-bit offsets. The value <tt>offset32<\/tt> is the 32-bit offset (little-endian) into the file, and the <tt>xx<\/tt> values are the bytes to match.<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>05<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>of<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>fs<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>et<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>32<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<td style=\"text-align: left;\"><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none;\"><tt>nn<\/tt> bytes<\/td>\n<td style=\"text-align: left;\">Terminator<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2&quot;\">Repeat as needed<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>06<\/tt>: Matching the 16-bit file size. The value <tt>size<\/tt> is the 16-bit file size (little-endian).<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>06<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>si<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>ze<\/tt><\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>07<\/tt>: Matching the 24-bit file size. The value <tt>size24<\/tt> is the 24-bit file size (little-endian).<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>07<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>si<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>ze<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>24<\/tt><\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>08<\/tt>: Matching the 32-bit file size. The value <tt>filesize<\/tt> is the 32-bit file size (little-endian).<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>08<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>fi<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>le<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>si<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>ze<\/tt><\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Finally, there is the &#8220;combo&#8221; detector. This allows you to combine multiple detectors (which must all be satisfied).<\/p>\n<p>Type <tt>FF<\/tt>: Combo detector. Each <tt>xx<\/tt> block is one of the other detector types (starting with the type byte and ending with the null terminator).<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>FF<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<td style=\"text-align: left;\"><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none;\"><tt>nn<\/tt> bytes<\/td>\n<td style=\"text-align: left;\">Terminator<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2&quot;\">Repeat as needed<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>For example, one of the detectors that comes with Windows 95 is <tt>ff0601023e0a03000306f05c00<\/tt>. This breaks down as<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: left;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>FF<\/tt><\/span><\/td>\n<td>Combo detector<\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>06<\/tt><\/span><\/td>\n<td>First detector is 6 bytes long<\/td>\n<\/tr>\n<tr>\n<td style=\"padding-left: 1em;\"><span style=\"border: solid 1px currentcolor;\"><tt>01<\/tt><\/span><\/td>\n<td>Type 1: Match NE header with 1-byte offsets<\/td>\n<\/tr>\n<tr>\n<td style=\"padding-left: 1em;\"><span style=\"border: solid 1px currentcolor;\"><tt>02<\/tt><\/span><\/td>\n<td>Match two bytes<\/td>\n<\/tr>\n<tr>\n<td style=\"padding-left: 1em;\"><span style=\"border: solid 1px currentcolor;\"><tt>3e<\/tt><\/span><\/td>\n<td>At offset <tt>0x3E<\/tt> in the NE header (expected Windows version)<\/td>\n<\/tr>\n<tr>\n<td style=\"padding-left: 1em;\"><span style=\"border: solid 1px currentcolor;\"><tt>0a<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>03<\/tt><\/span><\/td>\n<td>Bytes <tt>0a<\/tt>, <tt>03<\/tt>, indicating Windows version 3.1<\/td>\n<\/tr>\n<tr>\n<td style=\"padding-left: 1em;\"><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<td>Terminator<\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>03<\/tt><\/span><\/td>\n<td>Second detector is 3 bytes long<\/td>\n<\/tr>\n<tr>\n<td style=\"padding-left: 1em;\"><span style=\"border: solid 1px currentcolor;\"><tt>06<\/tt><\/span><\/td>\n<td>Type 6: Match 16-bit file size<\/td>\n<\/tr>\n<tr>\n<td style=\"padding-left: 1em;\"><span style=\"border: solid 1px currentcolor;\"><tt>f0<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>5c<\/tt><\/span><\/td>\n<td>File size <tt>0x5cf0<\/tt><\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>00<\/tt><\/span><\/td>\n<td>No more detectors<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In practice, you tend to see a lot of file size matches, because any change to a program is highly like to alter the file size. Conversely, you are unlikely to see many file contents matches because those incur additional I\/O and are therefore more expensive.<\/p>\n<p>If a match is found, the subkeys indicate the segments to patch, and the values of those subkeys are binary data providing the patch to apply. The names of the values are not significant, but traditionally &#8220;Add&#8221; patches are named <tt>Add<\/tt> and &#8220;Change&#8221; patches are named <tt>Change<\/tt>. If there is more than one Add or Replace patch, tradition dictates that they are given numeric suffixes to distinguish them.<\/p>\n<p>Type <tt>01<\/tt>: Change bytes. The <tt>sz<\/tt> is the total size of the patch value. The <tt>offs<\/tt> is a 16-bit (little-endian) offset into the segment. The <tt>xx<\/tt> values are the bytes expected to be there, and the <tt>yy<\/tt> values are the bytes that they will be changed to.<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>01<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>sz<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>of<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>fs<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>yy<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>yy<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>yy<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid solid;\"><tt>nn<\/tt> bytes<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none;\"><tt>nn<\/tt> bytes<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Type <tt>02<\/tt>: Append bytes. The <tt>sz<\/tt> is the total size of the patch value. The <tt>offs<\/tt> is a 16-bit offset (little-endian) to where the bytes should be added. (The offset must be greater than or equal to the actual segment size, and the segment will be grown to accommodate the extra bytes.) The <tt>xx<\/tt> values are the bytes to add.<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>02<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>sz<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>of<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>fs<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>nn<\/tt><\/span><\/td>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span> \u2026 <span style=\"border: solid 1px currentcolor;\"><tt>xx<\/tt><\/span><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid solid;\"><tt>nn<\/tt> bytes<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>For example, the detector above comes with this patch: <tt>0109700002ff76eb15<\/tt>. This breaks down as follows:<\/p>\n<table class=\"cp3\" style=\"border-collapse: separate; text-align: left;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>01<\/tt><\/span><\/td>\n<td>Change bytes<\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>09<\/tt><\/span><\/td>\n<td>Total size of this entry is 9 bytes<\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>70<\/tt><\/span><span style=\"border: solid 1px currentcolor; border-left: none;\"><tt>00<\/tt><\/span><\/td>\n<td>Segment offset is <tt>0x0070<\/tt><\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>02<\/tt><\/span><\/td>\n<td>Change two bytes<\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>ff<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>76<\/tt><\/span><\/td>\n<td>Original bytes are <tt>ff<\/tt> <tt>76<\/tt><\/td>\n<\/tr>\n<tr>\n<td><span style=\"border: solid 1px currentcolor;\"><tt>eb<\/tt><\/span> <span style=\"border: solid 1px currentcolor;\"><tt>15<\/tt><\/span><\/td>\n<td>Change them to <tt>eb<\/tt> <tt>15<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>I chose this example because it&#8217;s one of the patches I wrote. It fixes a bug in a sound card driver that corrupts the upper 16 bits of extended 32-bit registers in a hardware interrupt handler. The corruption happens in a debug logging function, so the patch replaces a section of the logging function with <tt>eb<\/tt> <tt>15<\/tt>, which is the encoding of an unconditional jump forward by <tt>0x15<\/tt> bytes. This skips over the section that corrupts the registers and resumes execution at a harmless point later in that function.<\/p>\n<p>The corruption happens because the driver calls a function which corrupts the upper 16 bits of extended 32-bit registers, as is permitted by normal 16-bit code. However, hardware interrupt handlers operate under stricter conditions than normal 16-bit code, and the function in question is not documented as safe to call from a hardware interrupt. This code was always broken, but they mostly got away with it prior to Windows 95.<\/p>\n<p>Before this change, the driver corrupted registers during a hardware interrupts, resulting in unpredictable behavior in the code that was interrupted. (See also: <a title=\"Memory corruption from outside the process looks like space aliens\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250123-00\/?p=110800\"> Space aliens<\/a>.)<\/p>\n<p>Now, with this change, the logging never executes either, but the only place the message gets logged to is the debug terminal, so the only people who see these messages are developers. If the sound card vendor wants to see these messages on their debug terminal, they can fix their bug.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Replacing bytes with the greatest of care.<\/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":[2],"class_list":["post-111781","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Replacing bytes with the greatest of care.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111781","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=111781"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111781\/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=111781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}