产品终局:每个变化都充满重大风险,第二集

The Old New Thing (Raymond Chen) 新闻

摘要

关于Word 97中因CPU勘误导致的偶发性bug的历史记录,通过二进制补丁解决,以最小化发布周期中的风险。

<p>一位同事讲述了这个在Word 97发布周期最后阶段出现的bug的故事。</p> <p>测试团队在一个较为常见的代码路径中发现了一个阻碍发布的bug。坏消息是这个bug是偶发的。好消息是测试团队编写了一个脚本,能在实验室中以相当好的可靠性触发崩溃。坏消息是当你使用调试器时,bug就消失了。</p> <p>开发团队非常焦虑,因为这种仅在实验室中偶发出现的bug<a title="百万分之一的概率就在下周二" href="https://learn.microsoft.com/en-us/archive/blogs/larryosterman/one-in-a-million-is-next-tuesday">在实际使用中会经常出现</a>。但是,如何调试一个抵抗调试的问题呢?</p> <p>有人建议使用在线仿真器(ICE),它基本上是一台运行CPU仿真器的<a title="在线仿真:用于软件调试的强大硬件工具" href="https://www.rcollins.org/ddj/Jul97/">独立计算机</a>。ICE有一根电缆插入目标机器的CPU插座,这就是ICE能够仿真CPU操作的机制:通过物理复制真实CPU会产生的电CPU被仿真,你可以使用ICE在CPU内部发生的事情上设置断点,比如“当CPU禁用中断时,将值42写入此内存位置时中断”。(尽管在这种情况下,它只是用于从外部系统设置断点和检查内存。)对于大多数软件开发者来说,在线仿真器只存在于神话中,获得并使用它的可能性让五岁的小男孩得知他可能乘坐消防车时一样兴奋。</p> <p>领导调查的开发者们欣喜若狂,当他们发现大多数崩溃系统来自同一制造商,并且都是在特定日期之前制造的。此时,不久之后就发现了一个CPU勘误,与受影响系统的制造日期相符。</p> <p>现在,他们使用的编译器已经发布了更新以避免有问题的代码序列,但团队在更新可用之前已经锁定了他们的工具集,并且在<a title="微话语:托管" href="https://devblogs.microsoft.com/oldnewthing/20260217-00/?p=112067">托管期间</a>升级编译器不是个好主意,因为谁知道切换到新编译器会引入哪些新bug。²</p> <p>团队编写了一个工具来扫描他们的二进制文件,查找任何可能触发CPU勘误的代码序列。²他们发现了大约150个有问题的代码序列实例,但CPU错误的一个要求是序列跨越页面边界,而这150个实例中只有一个跨越了页面边界。</p> <p>而且他们的测试人员找到了它。</p> <p>为了避免修复引入任何新问题,团队选择对二进制文件进行二进制补丁,在有问题的代码序列中插入一个<code>nop</code>。这足以避免CPU勘误,而不会让其他代码面临回归风险。</p> <p><b>额外阅读</b>:<a title="产品终局:每个变化都充满重大风险" href="https://devblogs.microsoft.com/oldnewthing/20091104-01/?p=16143">相关故事</a>。</p> <p>¹ 补充阅读:<a title="微话语详解:托管不只是发布候选版本的另一个名字吗?" href="https://devblogs.microsoft.com/oldnewthing/20260623-00/?p=112462">托管 vs. 发布候选版本</a>。</p> <p>² 编译器可能有bug被产品源代码触发的风险很小,但更大的风险是产品源代码中存在预存在的bug,这些bug会被新编译器暴露。例如,未初始化的变量bug可能被旧编译器的内存布局选择所掩盖,因为之前的内存使用是一个从未为null的指针,但新编译器对局部变量的布局不同,现在之前的内存使用是一个有时为零的整数。</p> <p><a title="我的,你有什么奇怪的NOP!" href="https://devblogs.microsoft.com/oldnewthing/20110112-00/?p=11773">听起来熟悉吗</a>?</p> <p>帖子<a href="https://devblogs.microsoft.com/oldnewthing/20260826-00/?p=112649">产品终局:每个变化都充满重大风险,第二集</a>首次出现在<a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>。</p>
查看原文
查看缓存全文

缓存时间: 2026/08/28 03:49

# 在产品发布的最终阶段,任何改动都充满风险(第二辑)—— 新事物中的旧问题 来源:https://devblogs.microsoft.com/oldnewthing/20260826-00?p=112649 一位同事讲述了 Word 97 发布周期末期出现的一个漏洞故事。 测试团队在一个较为常用的代码路径中发现了一个足以叫停发布的漏洞。坏消息是,这个漏洞时有时无;好消息是,测试团队编写了一个脚本,能在实验室环境中以相当高的可靠性重现崩溃。坏消息是,一旦使用调试器,这个漏洞就消失了。 开发团队十分焦虑,因为一个在实验室里只是零星出现的漏洞,在实际使用中往往会频繁发生(https://learn.microsoft.com/en-us/archive/blogs/larryosterman/one-in-a-million-is-next-tuesday)。但如何调试一个“抗拒”调试的问题呢? 有人提议使用在线仿真器(ICE),这本质上是一台运行 CPU 仿真器的独立计算机(https://www.rcollins.org/ddj/Jul97/)。ICE 有一根电缆插在目标主机的 CPU 插槽上,这是它能够模拟 CPU 运行的方式:通过物理再现真实 CPU 产生的电信号。既然 CPU 是被模拟的,你就可以使用 ICE 在 CPU 内部发生的事件上设置断点,比如“当 CPU 禁用中断时,将值 42 写入此内存地址时中断。”(不过在这个案例中,它仅用于设置断点和从外部检查内存。)对于大多数软件开发者而言,在线仿真器只存在于传说中,能够获得并使用它的可能性,让兴奋劲儿就像五岁小男孩听说可能要去乘坐消防车。 当主导调查的开发者发现大多数崩溃系统都来自同一家制造商,并且都在某个特定日期之前生产时,他们欣喜若狂。不久之后,他们就找到了一个与受影响系统生产日期相符的 CPU 勘误。 当时,他们使用的编译器已经发布了更新,以避免这段有问题的代码序列,但团队在该更新发布前就锁定了他们的工具集。而在代码冻结期间升级编译器(https://devblogs.microsoft.com/oldnewthing/20260217-00/?p=112067)1 并不是个好主意,因为谁知道切换到新编译器会引入什么新漏洞。2 团队编写了一个工具来扫描他们的二进制文件,查找任何会触发该 CPU 勘误的代码序列。2 他们发现了大约 150 处有问题的代码序列,但触发 CPU 漏洞的一个条件是该序列必须跨越一个内存页边界,而这 150 处中只有一处跨越了页边界。 而他们的测试人员恰恰就发现了它。 为了避免修复工作附带引入任何新问题,团队选择对二进制文件进行二进制补丁,在有问题的代码序列中插入一个 `nop`(空操作指令)。这足以避免触发 CPU 勘误,又不会让其他代码产生回归风险。 **延伸阅读**:相关故事 (https://devblogs.microsoft.com/oldnewthing/20091104-01/?p=16143)。 1 补充阅读:代码冻结与发布候选版 (https://devblogs.microsoft.com/oldnewthing/20260623-00/?p=112462)。 2 编译器本身存在 bug 并被产品源代码触发的风险虽然存在,但更大的风险在于,产品源代码中已存在的 bug 可能会被新编译器暴露出来。例如,一个未初始化变量的 bug 可能因为旧编译器的内存布局方式而被掩盖——之前的内存使用恰好是一个指针且其值从不为空;但新编译器对局部变量的布局不同,导致之前的内存使用可能是一个有时为零的整数。 听起来是不是很耳熟 (https://devblogs.microsoft.com/oldnewthing/20110112-00/?p=11773)? ### 分类 ### 主题 ## 作者 Raymond Chen Raymond 涉足 Windows 的演变已超过 30 年。2003 年,他创建了一个名为“新事物中的旧问题”(The Old New Thing)的网站,其受欢迎程度远远超出了他最疯狂的想象,这一发展至今仍让他感到惶恐不安。该网站后来催生了一本书,巧合的是,书名也叫《新事物中的旧问题》(Addison Wesley 2007)。他偶尔会出现在 Windows 开发文档的 Twitter 账户上,讲述一些毫无实用信息的故事。

相似文章

2026年6月创纪录的补丁星期二

Krebs on Security

微软2026年6月补丁星期二创下纪录,修复了近200个安全漏洞,其中包括三个已被公开利用的零日漏洞。人工智能工具越来越多地被用于发现漏洞,安全研究员如Nightmare Eclipse发布漏洞利用代码。

2026年4月补丁星期二版本

Krebs on Security

微软2026年4月补丁星期二修复了创纪录的167个漏洞,包括一个正在被积极利用的SharePoint零日漏洞和一个公开披露的Windows Defender漏洞(BlueHammer),同时Google Chrome和Adobe Reader也修复了零日漏洞。