---
title: "Word 97 stopped crashing as soon as the debugger arrived"
locale: "en"
url: "https://irz.fr/en/articles/word97-debugger-cpu-erratum-en"
markdown_url: "https://irz.fr/en/articles/word97-debugger-cpu-erratum-en.md"
category: "tech"
tags: ["Word 97", "debugging", "CPU", "erratum", "release engineering"]
published_at: "2026-08-31T12:50:00.000Z"
author: "Léa Perrin"
translation: "https://irz.fr/fr/articles/word97-debugger-cpu-erratum-fr.md"
---

# Word 97 stopped crashing as soon as the debugger arrived

Near the end of Word 97 development, a reproducible crash vanished under a debugger. Microsoft traced it to a CPU erratum and patched one binary sequence with a NOP instead of changing compilers.

The test could crash Word 97. The failure was sporadic, yet the script brought it back often enough that a team near release had no reason to gamble on users never seeing it.

Then somebody ran the debugger.

No crash.

Raymond Chen tells the story nearly thirty years later from a colleague’s account. The bug affected a fairly common code path and was considered **ship-stopping**: serious enough to hold the release until the team understood it. The lab even had a script that triggered the failure with fairly good reliability.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

They had something rare and valuable in bug hunting: a script that could summon the failure. Then the moment a debugger joined the experiment, that advantage evaporated.

Chen does not say exactly why the crash vanished. Chen leaves that hole open. A debugger can disturb timing, memory state, code through breakpoints, and plenty more, but none of those explanations is identified in the account. Picking one would be fan fiction for engineers.

> **The bug retreats**
> - A test script crashes Word 97 with decent reliability.: 1
> - The path is common enough for the bug to block release.: 2
> - Under a debugger, the crash stops happening.: 3
> - The investigation has to continue without direct observation of the failure.: 4
> The source does not explain why the debugger changes the behavior. That part remains unknown.

## Another observer

At one point the team considered hauling in hardware that most software developers only knew as legend: an **ICE**, an in-circuit emulator.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

In Chen’s account, this hardware effectively stands in for the target machine’s CPU. A cable plugs into the processor socket while the emulator reproduces the electrical signals a real processor would generate. Engineers can inspect memory and events from outside the system they are trying to understand.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

The appeal was almost physical: if software observation changed the result, move the observation outside the target machine’s normal CPU path.

The ICE never becomes the hero.

Instead, developers notice something much more ordinary about the failing machines: most came from the **same manufacturer**, and they had been built before a certain date. That cluster led them to a CPU erratum consistent with the manufacturing dates of the affected systems.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

Chen names neither the manufacturer nor the processor model. He also does not publish the exact instruction pattern. The evidence therefore stops at a careful statement: **a known hardware erratum could be triggered by a particular code sequence under specific conditions**.

The suspicion had moved down a layer. Word could be emitting legal machine code while a particular processor revision still mishandled the exact sequence under the exact wrong conditions.

## About 150 patterns

The compiler used by the Word team had already received an update that avoided the offending sequence.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649) That presented the obvious fix: rebuild Word and let the newer code generator avoid the pattern everywhere. Near the end of a release, though, “obvious” and “safe” are annoyingly different words. The team kept the old toolchain.

Instead it wrote a tool that scanned the existing binaries for every occurrence of the sequence capable of triggering the erratum. It found **around 150 occurrences**.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

This is where the primary post is better than the retelling. *The Register* compresses the search down to one occurrence.[5](https://www.theregister.com/software/2026/08/28/word-97s-ghost-in-the-machine-the-crash-that-vanished-the-moment-anyone-looked_at_it/5293263) Chen says the scanner actually found about 150 candidate sequences. The useful filter came next.

The processor bug required one more condition. The sequence also had to **span a memory page boundary**. Of those roughly 150 occurrences, only one did.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

And the testers had found it in practice.

> **150 → 1**
> - binary sequences matching the dangerous pattern: ≈150
> - sequence that also crossed a page boundary: 1
> - patch added at the offending location: 1 NOP
> - documented explanation for why debugging hid the crash: 0
> The scan turns a ghostly crash into an extremely narrow hardware condition.

A page boundary is an excellent ingredient for a miserable bug. The same bytes can sit harmlessly in one place and become dangerous when their address makes the sequence straddle two pages. Reading the source alone will never show that condition. The address is part of the bug.

So the rarity lived less in the instruction pattern than in its address. About 150 candidates existed. Only one landed where every condition lined up.

## Do not recompile

The newer compiler still looks like the adult solution. Unfortunately Word 97 was in the part of the schedule where adult solutions can have enormous blast radii.

Microsoft called this stage **escrow**. Chen’s 2026 explanation is wonderfully final: this is the build expected to ship if it clears quality and reliability targets.[2](https://devblogs.microsoft.com/oldnewthing/20260623-00/?p=112462) The culture around it is basically hands off unless the emergency is real.

Changing compilers at that point does not alter one bad sequence. It can regenerate a large amount of machine code.

The risk is not necessarily that the new compiler contains a bug. Chen gives a nastier example: an existing source bug can remain hidden by the old compiler’s layout of local variables. Change compiler, change the layout, and an uninitialized value that happened to look harmless can suddenly become zero.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

A perfectly correct new compiler could therefore expose a perfectly old defect simply by arranging locals differently in memory.

Chen has a nastier example from Windows 3.1. A tiny fix added one global variable. That moved the globals sitting after it, so an old corruption bug that had harmlessly been writing zero onto an already-zero variable suddenly hit something important.[4](https://devblogs.microsoft.com/oldnewthing/20091104-01/?p=16143) Nothing about the bad write was new. Its victim was.

Near release, **source diff size is a poor measure of actual change size**.

> **Two fixes**
> - Automatically avoids the sequence, but regenerates lots of code and can alter layouts and other already-tested behavior.: New compiler
> - Changes only the one occurrence satisfying every condition of the CPU erratum.: Binary patch
> At this point, elegance matters less than minimizing regression surface.

## A useless byte

The shipped workaround fit into one instruction: `nop`.

A NOP, short for *no operation*, deliberately contributes no useful result. The processor consumes it and moves on. Dropping one into the offending pattern was enough to stop that exact dangerous sequence from reaching the CPU unchanged.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)

It did not fix the processor. It was not a conceptual repair of Word’s source code either. It was a targeted avoidance of a known hardware condition.

Chen described another case in 2011 where this sort of surgery was routine, this time involving early **B1 stepping 80386** processors and Windows 95.[3](https://devblogs.microsoft.com/oldnewthing/20110112-00/?p=11773) Several errata on those chips depended on exact adjacency between instruction types. Inserting a NOP between them could break the dangerous combination. In some cases even an ordinary NOP fell into an inconvenient category, so engineers used a specially prefixed form.[3](https://devblogs.microsoft.com/oldnewthing/20110112-00/?p=11773)

The 2011 story is a useful analogy and a terrible identification tool. It does **not** tell us that Word 97 hit the same 80386 B1 issue. What it does show is the engineering pattern: a NOP can act like a tiny spacer in an x86 instruction stream, breaking a combination the hardware dislikes.

The Word 97 patch follows that same minimal-mitigation philosophy.

## The known bug

There is something counterintuitive about the decision. The team now knew of a newer compiler that generated safer code around the erratum. It still kept the older toolchain and modified the binary directly.

Early in a project, binary-patching around a CPU bug should raise eyebrows. A few steps from shipping, the arithmetic is different. The existing build had accumulated an awkward asset: lots of boring test evidence. Source, compiler, options and generated binaries had been exercised together for weeks or months. Recompile everything and some of that evidence stops applying to the machine code you now intend to ship.

The NOP introduces a much smaller uncertainty. The team can verify that the one page-crossing occurrence no longer triggers the CPU bug and that the test scenario stops crashing, without asking all of Word 97 to become a new build in every meaningful sense.

> **Known / unknown**
> - One sequence, one page-boundary condition, one cluster of affected machines, one reproducing test.: Known bug
> - Whatever a broad toolchain change could rearrange across thousands of paths that had already been tested.: Unknown regression
> In the end game, living with understood behavior can be safer than creating a new class of unknown behavior.

Chen’s older Windows 3.1 story phrases the release lesson almost backwards from school deadlines: as shipping gets closer, the rate of change should **slow**, because regression risk starts costing more than many fixes are worth.[4](https://devblogs.microsoft.com/oldnewthing/20091104-01/?p=16143) Serious bugs still move the code. They just need a much better reason to move a lot of it.

## The ghost remains

The funniest part is still the one the story never closes: why did attaching the debugger make this particular crash vanish?

The published account does not say.[1](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649) Maybe the team knew at the time. Maybe the detail was lost. Maybe it simply stopped mattering once the erratum was identified. We do not need to choose for them.

What the story establishes is already enough.

A software crash led to a hardware defect. The dangerous pattern existed around 150 times, but only one copy occupied the wrong address relationship. A newer compiler knew how to avoid the pattern, but switching to it would broaden the risk to the whole product. An instruction that does nothing therefore became the safest fix.

The fix therefore ends with an instruction designed to do no useful work. For once, doing nothing was exactly the feature the release needed.

## References

1. [Raymond Chen / Microsoft — In the product end game, every change carries significant risk, episode 2, 26 August 2026](https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649)
2. [Raymond Chen / Microsoft — Microspeak elaborated: Isn’t escrow just a release candidate by another name?, 23 June 2026](https://devblogs.microsoft.com/oldnewthing/20260623-00/?p=112462)
3. [Raymond Chen / Microsoft — My, what strange NOPs you have!, 12 January 2011](https://devblogs.microsoft.com/oldnewthing/20110112-00/?p=11773)
4. [Raymond Chen / Microsoft — In the product end game, every change carries significant risk, 4 November 2009](https://devblogs.microsoft.com/oldnewthing/20091104-01/?p=16143)
5. [The Register — Word 97's ghost in the machine, 28 August 2026](https://www.theregister.com/software/2026/08/28/word-97s-ghost-in-the-machine-the-crash-that-vanished-the-moment-anyone-looked_at_it/5293263)
