这是Quora上的一个问题,米克的回答获得了13.5k的“赞”。他是这样回忆的:有一次一个心理学博士找我查一个BUG,程序是他的一个学生写的,经常会出现奇怪的输出。该程序所做的是从文件中读取数据,提出50个问题,进行一系列计算,然后根据博士的研究得出一个分数。该程序在大学的3B2上运行。他向我展示了程序并确认该错误是可重现的——每次我在问题之间切换时,总会闪烁一些奇怪的字符。我想这应该很容易,所以我答应了,我们同意按小时付款。Day1,来到这个3B2,用学生账号登录,找到用C写的源码,开始测试。代码的可读性很差,所有的代码都写在一行上,变量名都是三个字母,而且是随意组合的!我很高兴我选择了按小时收费。我已将代码格式化为惯用的样式,因此它具有一定的可读性。完成后,我使用curses库移动到屏幕上的某个位置,打印问题和答案,然后等待响应。但是打印第一行后,出现了一些乱码,大约1/2秒后,乱码被题目覆盖了。这个问题应该很容易解决,需要打印信息的地方只有五个,而且都是一闪而过的乱码。小东西,删掉mvpwintw()应该就可以了。我删了之后开始编译,感觉问题解决的差不多了。但是运行的时候,干扰信息又出现了!只是乱码变了,但症状还是一样!我查看了代码,发现又回到了我改之前的样子!15个文件、混乱的格式、三个字母的变量。为什么一开始不备份代码,我真想拍自己。我再次格式化它们,这次将代码放入三个不同名称的文件中。然后备份整个文件夹并设置权限为只读。编译后,一切正常。运行后,该文件夹中出现了15个文件!源码我改了之后没有删除,然后又出现了杂音信息。我想通了,肯定是硬盘某处的代码,编译的时候会把程序添加到我修改的代码中。所以我要搜索include区(/usr/include),因为我们用的是research版本,所以机器上除了kernel以外的代码都在。头文件太多了,在3B2上搜索需要一些时间。以上是第一天的工作。Day2没有从磁盘搜索中得到任何结果,这意味着乱码要么被加密,要么在库中的某个地方。可是怎么也找不到,我决定把所有的文本文件都搜一遍,这次比昨天用的时间还长,第二天就这样过去了。Day3没有结果。字符串已加密。我不得不根据所有的头文件一点一点地检查它。这花费了相当多的时间,我们警告学校有人可能已经获得了Phelps博士计算机的根访问权限。不过他们并不在意,说不定这只是一台实验室电脑而已。我打开了#include文件,没有发现任何代码。后来发现,这些被编译成一个文件。没关系,毕竟我们有源码,大不了要重新编译所有的库。Days4-6接下来的部分是最难的部分,我们终于把问题解释到学校课本上了。然后让Mark(我觉得他可以当Unix管理员,因为他娶了Dean的女儿)学习编译。***他终于同意让我做,因为他什么也做不了。Day6***,编译终于完成了。我把修改后的代码拿出来,重新开始编译。一切正常,然后我运行它,伙计!问题又来了。源代码拆分成15个文件,噪音又出来了。简直是变魔术了,感觉自己被打脸了,问题肯定不在源码上。菲尔普斯医生也有些不高兴。他觉得时隔这么久,也该写一篇新的了。“当然,”我失望地说,“你说得对,也许重写会更好。”“好吧,我们明天开始重写,”医生说。Day7见鬼去吧,我不认输!我对菲尔普斯博士说:“你不用再给我钱了,给我时间,我一定会找到这个bug的。”Days8-14我学聪明了,他一定修改了一些库,我开始研究编译好的汇编(虽然之前完全不懂汇编),从开始学习到最终理解汇编花了六天时间代码。虽然没有发现任何异常,但这完全是浪费时间。Day15突然,我意识到问题可能出在编译器上,一定是。每次编译代码时,编译器都会在源代码中添加噪音。我以前也听说过这种情况。啊耶!我找到了!我们还有编译器的源代码,我查了一下,幸好找到了。compiler-linker中的代码是这样的:1)检测所有对fopen()的调用,在打开的文件中寻找Dr.Phelps'question,如果找到2)编译时重写15个文件3)使用这15个文件来编译医生的程序,链接时会以-o的形式输出名字。该学生修改了编译器,将代码添加到Phelps博士的程序中。几天后,AT&T技术支持提供了原始的编译器和链接器代码,我们重新编译以替换修改后的编译器和链接器。但是,问题还没有解决。编译器被我们没有的其他源代码污染了。这些代码存在于当前的可执行编译器中,在编译编译器时会添加污染代码。但它并没有修改/usr/src中的代码,而是将其复制到一个隐藏文件夹中,修改编译器源码,编译,最后删除隐藏文件夹。AT&T花了很长时间才发现这个问题。学生修改了编译器以在编译器重新编译时添加污染代码。***我们不得不从另一台3B2机器上复制编译器的字节码文件版本,最终解决了这个问题。通过编译器的代码,我们还发现如果编译/sbin/login,会加入一些后门代码,允许任何人使用特定的密码登录root。可以通过调制解调器或Tymnet访问此计算机。最后,这件事引起了学校的注意。这人真是天才,也太可怕了吧!也有网友回答说这个bug只存在于产品中,开发版没有或者无法重现。bug触发的几率很小,但不能忽视纠正代码中不是你写的bug。原来写代码的人这家伙走了。出现bug的地方是99.9%可靠的库,这是你永远不会怀疑的地方。这些年很多人都尝试过修复这个bug,但是没有人因为逻辑错误的bug而成功,只有运行一段时间后才会触发debug。需要特定领域的知识。是你不明白。调试的期限非常紧迫。堆栈溢出挂断。分号键坏了。看着我一年前的代码,我感觉就像“我写了这该死的东西”。库中没有文档。客户改变了他们的要求。在错误的目录下,rm-rf"Mycodeworks,Idon'tknowwhy"(这句话不用翻译)Meeting,meeting,meeting...作为一个程序员,让我去死吧。那么,你的噩梦又是什么呢?
