惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
Recent Announcements
Recent Announcements
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog
罗磊的独立博客
月光博客
月光博客
J
Java Code Geeks
A
About on SuperTechFans
Microsoft Security Blog
Microsoft Security Blog
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
F
Fortinet All Blogs
U
Unit 42
C
Check Point Blog
Martin Fowler
Martin Fowler
有赞技术团队
有赞技术团队
博客园 - 叶小钗
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
阮一峰的网络日志
阮一峰的网络日志
MyScale Blog
MyScale Blog

The Old New Thing

Why do Microsoft job levels start in the high 50's instead of starting at a sane number like 1? - The Old New Thing Why didn't Read­Directory­ChangesW provide a way to correlate the two sides of a rename operation? - The Old New Thing How can I remove the Close button from my window caption? - The Old New Thing Why is the x86 undefined instruction called ud2? Why 2? - The Old New Thing What algorithm did Windows XP use to choose your initial user picture? - The Old New Thing A sample use of the winstart.bat file in Windows 95 - The Old New Thing Why don't we allow stacks to be sparse, instead of forcing them to be contiguous? - The Old New Thing What happens if you change a window class's GCL_CB­WND­EXTRA? - The Old New Thing The case of the progress callback that never got called when progress happened - The Old New Thing The perils of binding to value types in XAML - The Old New Thing Microspeak: Funded / unfunded - The Old New Thing AWE does not require PAE, though PAE makes it much more useful - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 2 - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 1 - The Old New Thing Why didn't the Windows Entertainment Pack just run the MS-DOS version inside an emulator? - The Old New Thing Comparing the two holograms on the Windows 95 box - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function, practical exam - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function - The Old New Thing On wrapping a callable in a lambda that just calls it with the same parameters - The Old New Thing Why did the Microsoft Entertainment Pack for Windows have a special sticker announcing that it also had Tetris? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing Forcing an ARM64X executable to run as a specific architecture - The Old New Thing A little helper class for managing LPPROC_THREAD_ATTRIBUTE_LISTs - The Old New Thing The comments that go into code versus those that go into the pull request description - The Old New Thing The little-known winstart.bat batch file - The Old New Thing How can I perform a Copy­File&shy in unbuffered mode? - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 5 - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 4 - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 3 - The Old New Thing
In the product end game, every change carries significant...
Raymond Chen · 2026-08-26 · via The Old New Thing

A colleague related this story of a bug that arose at the very end of the Word 97 release cycle.

Testing had identified a ship-stopping bug in a somewhat common code path. The bad news is that the bug was sporadic. The good news is that the test team had come up with a script that could trigger the crash in the lab with fairly good reliability. The bad news is that the bug went away when you used the debugger.

The development team was very anxious, because a bug that appears only sporadically in the lab is going to occur regularly in the wild. But how do you debug a problem that resists debugging?

There was talk of using an in-circuit emulator (ICE), which is basically a separate computer that ran a CPU emulator. The ICE had a cable that plugged into the target machine’s CPU socket, and that was the mechanism by which the ICE could emulate the operation of a CPU: by physically reproducing the electrical signals that a real CPU would generate. Since the CPU was emulated, you could use the ICE to set breakpoints on things that happen inside the CPU itself, like “Break when the value 42 is written to this memory location when the CPU has interrupts disabled.” (Though in this case, it was just for setting breakpoints and inspecting memory from outside the system.) To most software developers, in-circuit emulators existed only in myth, and the possibility of acquiring one and using it was met with the excitement of a five-year-old boy who learns that he might get to ride on a fire truck.

The developers who were leading the investigation beamed with joy when they identified that most of the crashing systems came from the same manufacturer, and they were all manufactured before a specific date. At this point, it wasn’t too long before a CPU errata was found that was consistent with the manufacturing dates of the affected systems.

Now, the compiler they were using had issued an update to avoid the offending code sequence, but the team had locked their toolset before that update became available, and upgrading the compiler while in escrow¹ is not a good idea, because who knows what new bugs would be introduced by switching to a new compiler.²

The team wrote a tool to scour their binaries to look for any occurrences of a code sequence that would trigger the CPU erratum.² They found around 150 instances of the troublesome code sequence, but one of the requirements for the CPU bug was that the sequence span a page boundary, and only one of those 150 incidents crossed a page boundary.

And their testers found it.

To avoid introducing any new problems as a side effect of the fix, the team opted to do a binary patch to the binary to insert a nop into the offending code sequence. This was enough to avoid the CPU erratum without risking regression to any other code.

Bonus reading: Related story.

¹ Supplemental reading: Escrow vs. release candidate.

² There is a small risk that the compiler will have a bug that is triggered by the product source code, but there is a much bigger risk that that there are pre-existing bugs in the product source code that would be exposed by the new compiler. For example, an uninitialized variable bug could be masked by the fact that the old compiler’s choice of memory layout means that the previous use of the memory was for a pointer that was never null, but the new compiler lays out local variables differently, and now the previous use of the memory was for an integer that is sometimes zero.

Sound familiar?

Category

Topics

Author

Raymond Chen

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.