您找到并修复过的最棘手的错误是什么?

时间:2008-10-04 04:03:35

标签: debugging

是什么让它很难找到?你是如何追踪它的?

不够近,但也看到了 https://stackoverflow.com/questions/175854/what-is-the-funniest-bug-youve-ever-experienced

73 个答案:

答案 0 :(得分:202)

在监控摄像机上运行的jpeg解析器,每次公司首席执行官进入房间时都会崩溃。

100%可重现的错误。

我不骗你!

这就是原因:

对于那些对JPEG压缩知之甚少的人来说 - 图像被分解成一个小块矩阵,然后使用魔法等进行编码。

当首席执行官进入房间时解析器窒息,因为他总是有一个方形图案的衬衫,这引发了一些特殊的对比和块边界算法。

真正的经典。

答案 1 :(得分:116)

这种情况并没有发生在我身上,但有一位朋友告诉我这件事。

他必须调试一个很少崩溃的应用程序。它只会在周三 - 9月 - 9日之后失败。是的,一年中的362天,一切都很好,一年中有三天会立即崩溃。

它会将日期格式化为“2008年9月22日星期三”,但缓冲区是一个字符太短 - 所以当你在一天中拥有2位数字的DOM时,它只会导致问题最长的一个月。

答案 2 :(得分:61)

这需要了解一些Z-8000汇编程序,我将在解释时解释。

我正在研究嵌入式系统(在Z-8000汇编程序中)。公司的另一个部门是在同一平台上构建一个不同的系统,并编写了一个函数库,我也在我的项目中使用它。错误是每次我调用一个函数时,程序崩溃了。我检查了所有的输入;他们很好。它必须是图书馆中的一个错误 - 除了图书馆已在全国数千个POS网站中使用(并且工作正常)。

现在,Z-8000 CPU有16个16位寄存器,R0,R1,R2 ...... R15,它们也可以作为8个32位寄存器寻址,命名为RR0,RR2,RR4..RR14等。库是从头开始编写的,重构了一堆较旧的库。它非常干净,遵循严格的编程标准。在每个函数的开头,将函数中使用的每个寄存器压入堆栈以保留其值。一切都很整洁&整洁 - 他们很完美。

尽管如此,我研究了该库的汇编列表,我发现该函数有些奇怪 - 在函数开始时,它有PUSH RR0 / PUSH RR2,最后有POP RR2 / POP R0 。现在,如果你没有遵循这一点,它会在开始时在堆栈上推送4个值,但最后只删除其中的3个值。这是灾难的秘诀。堆栈顶部有一个未知值,需要返回地址。该功能无法运作。

除此之外,我可以提醒你,它正在工作。它在成千上万台机器上被称为每天数千次。它不可能不起作用。

经过一段时间的调试(在使用80年代中期的工具的嵌入式系统上的汇编程序中并不容易),它总是会在返回时崩溃,因为坏的值是将它发送到随机地址。显然我必须调试工作应用程序,找出它没有失败的原因。

好吧,请记住,库非常适合保存寄存器中的值,所以一旦你将一个值放入寄存器,它就会保留在那里。 R1里面有0000。调用该函数时,它总是有0000。因此,该错误将0000留在堆栈上。因此,当函数返回时,它会跳转到地址0000,这恰好是一个RET,它将从堆栈中弹出下一个值(正确的返回地址),并跳转到该地址。这些数据完全掩盖了这个错误。

当然,在我的应用程序中,我在R1中有不同的值,所以它只是崩溃了....

答案 3 :(得分:51)

这是在Linux上,但几乎可以在任何操作系统上发生。现在大多数人可能都熟悉BSD套接字API。我们年复一年地愉快地使用它,并且它工作。

我们正在开发一个可以打开许多套接字的大规模并行应用程序。为了测试它的操作,我们有一个测试团队,可以打开数百个,有时超过一千个连接进行数据传输。使用最高频道号码,我们的应用程序将开始显示奇怪的行为。有时它只是崩溃了。另一次我们得到的错误根本不可能是真的(例如,accept()在后续调用中返回相同的文件描述符,这当然会导致混乱。)

我们可以在日志文件中看到出现问题,但很难确定。使用Rational Purify进行的测试表明没有错。但有些事情是错的。我们在这方面工作了好几天,并且越来越感到沮丧。它是一个showblocker,因为已经协商的测试会在应用程序中造成破坏。

由于错误只发生在高负载情况下,我仔细检查了我们对套接字所做的一切。我们从未测试过Purify中的高负载情况,因为在这种内存密集的情况下它是不可行的。

最后(幸运的是)我记得大量的套接字可能是select()的问题,它等待套接字上的状态变化(可能读/写/错误)。我们的应用程序确实在它到达带有描述符1025的套接字的那一刻就开始肆虐。问题是select()与位字段参数一起工作。位字段由宏FD_SET()和朋友填写,不会检查它们的参数是否有效。

因此,每当我们获得超过1024个描述符(每个操作系统都有自己的限制,Linux vanilla内核有1024个,实际值定义为FD_SETSIZE)时,FD_SET宏会愉快地覆盖其位字段并将垃圾写入下一个结构中。记忆。

我用poll()替换了所有select()调用,这是一个精心设计的替代arcane select()调用,而高负载情况从来就不是问题。我们很幸运,因为所有套接字处理都在一个框架类中,15分钟的工作可以解决问题。如果select()调用遍布整个代码,情况会更糟。

经验教训:

  • 即使API函数已有25年历史且每个人都使用它,它也可能有一个你还不知道的黑暗角落

  • API宏中未经检查的内存写入是EVIL

  • 像Purify这样的调试工具对所有情况都无济于事,特别是当使用大量内存时

  • 如果可能,请始终为您的应用程序提供框架。使用它不仅可以提高可移植性,还可以在API错误的情况下提供帮助

  • 许多应用程序在不考虑套接字限制的情况下使用select()。所以我很确定你可以通过简单地使用许多套接字来导致许多流行软件中的错误。值得庆幸的是,大多数应用程序永远不会超过1024个套接字。

  • 操作系统开发人员不喜欢安全的API,而是将责任归咎于开发人员。 Linux select()手册页说

  

“这些宏的行为是   如果描述符值是undefined,则为undefined   小于零或大于或   等于FD_SETSIZE,这是正常的   至少等于最大数量   的支持描述符   系统“。

这是误导。 Linux可以打开超过1024个套接字。并且行为绝对定义明确:使用意外值会破坏正在运行的应用程序。开发人员只是覆盖其他结构,而不是让宏对非法值有弹性。 FD_SET在linux头文件中实现为内联汇编(!),并将评估为单个汇编器写入指令。没有丝毫限制检查在任何地方发生。

要测试您自己的应用程序,您可以通过在main()之后直接以编程方式打开FD_SETSIZE文件或套接字然后运行应用程序来人为地夸大使用的描述符数量。

Thorsten79

答案 4 :(得分:43)

我是一个硬件问题......

当天早些时候,我使用了带有21英寸CRT显示器的DEC VaxStation。我们搬到了新大楼的一个实验室,在房间的两个角落安装了两个VaxStation。上电后,我的显示器闪烁就像一个迪斯科舞厅(是的,这是80年代),但另一个显示器没有。

好的,换掉显示器。另一台显示器(现在连接到我的VaxStation)闪烁,而我以前的显示器(移动到整个房间)没有。

我记得基于CRT的显示器对磁场很敏感。实际上,它们对于60Hz的交变磁场是非常可接受的。我立即怀疑我工作区域的某些东西产生了60赫兹的改变磁场。

起初,我怀疑在我的工作区域。不幸的是,即使关闭所有其他设备并拔下电源插头,显示器仍然会闪烁。那时,我开始怀疑楼里有什么东西。

为了测试这个理论,我们将VaxStation及其85磅显示器转换为便携式系统。我们将整个系统放在滚动推车上,并将其连接到100英尺的橙色结构延长线上。计划是将此设置用作便携式场强计,以便找到有问题的设备。

滚动显示器让我们感到很困惑。显示器正好在房间的一半闪烁,但不是另一边。房间呈正方形,门对面的角落,监视器在连接门的诊断线的一侧闪烁,但不在另一侧。房间四面环绕着走廊。我们将显示器推入走廊,闪烁停止了。事实上,我们发现闪烁只发生在房间的一个三角形的一半,而不是其他地方。

经过一段时间的混乱,我记得房间有一个双向天花板照明系统,每扇门都有灯开关。那一刻,我意识到出了什么问题。

我将显示器移动到房间的一半有问题,并关闭了天花板灯。闪烁停止了。当我打开灯时,闪烁恢复。从任一灯开关打开或关闭灯,在房间的一半内打开或关闭闪烁。

这个问题是由于有人在连接天花板灯时偷工减料造成的。在照明电路上连接双向开关时,在SPDT开关触点之间连接一根导线,从一个开关上的公共线穿过灯,然后连接到另一个开关上的公共线。

通常情况下,这些电线是并排在一起的。它们从一个开关盒中作为一组离开,运行到顶部天花板固定装置,然后运行到另一个盒子上。关键的想法是,所有载流导线都是并排在一起的。

当建筑物接线时,开关和灯之间的单线穿过天花板,但在开关之间传输的电线穿过墙壁。

如果所有导线彼此靠近并且彼此平行,则由一根导线中的电流产生的磁场被附近导线中的相等和相反电流产生的磁场抵消。不幸的是,灯的实际接线方式意味着房间的一半基本上位于大型单匝变压器初级线圈内。当灯亮起时,电流在一个环路中流动,而可怜的监视器基本上就坐在一个大型电磁铁内。

故事的道德:交流电源线中的热线和中性线彼此相邻是有充分理由的。

现在,我所要做的就是向管理层解释为什么他们必须重新布线他们新建筑的一部分......

答案 5 :(得分:35)

你遇到一些代码的错误,在研究完之后你会得出结论:“这种方法根本无法发挥作用!”突然它停止工作,虽然它总是在以前工作。

答案 6 :(得分:29)

我在工作中帮助构建的产品之一是在客户站点上运行了几个月,收集并愉快地将收到的每个事件记录到SQL Server数据库中。它运行了大约6个月,收集了大约3500万条记录。

然后有一天,我们的客户问我们为什么数据库近两周没有更新。经过进一步调查,我们发现正在进行插入的数据库连接无法从ODBC调用返回。值得庆幸的是,执行录制的线程与其余线程分开,允许除录制线程之外的所有内容继续正常运行近两周!

我们连续几个星期都尝试在除此之外的任何机器上重现问题。我们永远无法重现这个问题。不幸的是,我们的其他几个产品然后以相同的方式开始失败,其中没有一个将其数据库线程与其余功能分开,导致整个应用程序挂起,然后必须每次手动重新启动坠毁。

调查周变成了几个月,我们仍然有相同的症状:在我们使用数据库的任何应用程序中都有完整的ODBC死锁。到目前为止,我们的产品充斥着调试信息以及确定出错的方法,甚至可以确定某些产品会检测到死锁,收集信息,向我们发送结果,然后重新启动。

有一天在服务器上工作时,仍在从应用程序崩溃时收集调试信息,试图弄清楚发生了什么,服务器BSoD就在我身上。当服务器重新上线时,我在WinDbg中打开了minidump以找出违规驱动程序是什么。我得到了文件名并将其追溯到实际文件。在检查了文件中的版本信息后,我发现它是计算机上安装的McAfee防病毒套件的一部分。

我们禁用了防病毒软件,并且自!!以来没有出现任何问题

答案 7 :(得分:26)

我只是想指出一个相当普遍和讨厌的错误,可以在这个谷歌区域时间发生:
代码粘贴和臭名昭着的负面

当你复制粘贴一些带有minus的代码时,而不是常规的ASCII字符连字符 - 减号(' - ')

alt text
另外,减去(U + 2212),连字符 - 减号(U + 002D)

现在,即使在某些编辑器(或在DOS shell窗口)上,减号被假定为长于连字符 - 减号,取决于所使用的字符集,它实际上呈现为常规' - '连字符 - 减号。

而且......你可以花几个小时试图找出为什么这个代码不能编译,逐个删除每一行,直到找到实际原因!

可能不是最棘手的错误,但令人沮丧;)

(感谢ShreevatsaR在原帖中发现反转 - 请参阅评论)

答案 8 :(得分:19)

首先是我们发布的产品出现了一个错误,但是当我尝试调试问题时,它没有发生。我一开始认为这是一个“发布与调试”的东西 - 但即使我在发布模式下编译代码,我也无法重现这个问题。我去看看是否有其他开发人员可以重现这个问题。不。经过对程序输出的大量调查(产生混合汇编代码/ C代码列表)并逐步完成已发布产品的汇编代码(哎呀!),我找到了违规行。但这条线对我来说很好看!然后,我必须查找汇编指令的作用 - 并且确定已发布的可执行文件中的错误汇编指令。然后我检查了我的构建环境生成的可执行文件 - 它有正确的汇编指令。事实证明,构建机器以某种方式损坏并且仅为该应用程序的一条指令产生了错误的汇编代码。其他所有内容(包括我们产品的早期版本)都会向其他开发人员机器生成相同的代码。在向软件经理展示我的研究成果后,我们很快重新构建了我们的构建机器。

答案 9 :(得分:17)

网络应用程序的深处某处是(简化)行:

if (socket = accept() == 0)
    return false;

//code using the socket()

通话成功后发生了什么? socket设置为1. {1}}给1时做了什么? (例如:

send()

它打印到send(socket, "mystring", 7); ...这是我发现4小时后想知道为什么,我的所有stdout被取出后,我的应用程序正在打印到终端窗口而不是发送数据网络。

答案 10 :(得分:15)

对于80年代的数据通用小型机上的FORTRAN,我们遇到了一个情况,即编译器导致常数1(一)被视为0(零)。之所以发生这种情况是因为一些旧代码将值1的常量传递给一个函数,该函数将该变量声明为FORTRAN参数,这意味着它(应该是)不可变的。由于代码中存在缺陷,我们对参数变量进行了赋值,编译器兴高采烈地将其用于常量1的内存位置中的数据更改为0.

许多不相关的函数后来我们有代码与文字值1进行比较,测试失败。我记得在调试器中查看代码的时间最长。我打印出变量的值,它将是1但测试'if(foo .EQ.1)'将失败。我花了很长时间才想要让调试器打印出它认为1的值是什么。然后它花了很多头发来追溯代码,找出常数1变为0的时间。

答案 11 :(得分:13)

不是很强硬,但是当它被揭开时我笑了很多。

当我为网上商店维护一个24/7订单处理系统时,一位客户抱怨他的订单被“截断”了。他声称,虽然他所下的命令实际上包含了N个职位,但系统接受了更少的职位,没有任何警告。

在我们追踪订单流经系统后,揭示了以下事实。有一个存储过程负责在数据库中存储订单项。它接受了一个订单项列表作为字符串,它编码(product-id, quantity, price)三元组列表,如下所示:

  

“< 12345,3,19.99>< 56452,1,   8.99>< 26586,2,12.99>“

现在,存储过程的作者太聪明了,无法使用普通的解析和循环。因此,他将"<"替换为"insert into ... values (",将">"替换为");",直接将字符串转换为SQL多插入语句。如果他没有将结果字符串存储在varchar(8000)变量中,这一切都很好,花花公子!

发生的事情是他的"insert ...; insert ...;"被截断为第8000个字符而且对于那个特定的顺序,剪切是“幸运的”足以在insert之间发生,因此截断的SQL在语法上保持不变正确

后来我发现sp的作者是我的老板。

答案 12 :(得分:12)

Sun Microsystems的Bryan Cantrill就他使用他帮助开发的名为dtrace的工具追踪的一个错误提供了一个出色的Google Tech Talk。

The Tech Talk有趣,令人讨厌,内容丰富,令人印象深刻(,约78分钟)。

我不会在这里给出任何破坏者的错误,但他会在53:00左右开始揭露罪魁祸首。

答案 13 :(得分:12)

在测试我最近添加到交易应用程序中的一些新功能时,我碰巧注意到显示某种交易结果的代码永远不会正常工作。在查看了源代码控制系统之后,很明显这个bug已经存在了至少一年,而且我很惊讶没有一个交易者曾经发现它。

经过一段时间的困惑并与同事核实后,我修复了错误并继续测试我的新功能。大约3分钟后,我的电话响了。在另一端是一个愤怒的交易员,他抱怨他的一笔交易没有正确显示。

经过进一步调查,我意识到交易者遇到了我在3分钟前在代码中注意到的完全相同的错误。这个错误已经存在了一年,只是等待开发人员过来并发现它以便它可以实现真正的打击。

这是一种称为Schroedinbug的错误的好例子。虽然我们大多数人都听说过这些奇特的实体,但是当你在野外遇到一个实体时,这是一种令人毛骨悚然的感觉。

答案 14 :(得分:12)

当我认为C ++和数字手表非常整洁时,这又回来了......

我因能够解决困难的内存泄漏而享有声誉。另一支队伍发生了无法追查的漏洞。他们让我调查。

在这种情况下,它们是COM对象。在系统的核心是一个组件,它给出了许多曲折的小COM对象,它们看起来或多或少相同。每个客户都分发给许多不同的客户,每个客户负责执行相同次数的AddRef()Release()

没有办法自动计算谁调用了每个AddRef,以及他们是否有Release d。

我在调试器中花了几天时间,在小纸片上写下十六进制地址。我的办公室满满的。最后我找到了罪魁祸首。向我求助的团队非常感激。

第二天我换成了GC语言。*

(*实际上并非如此,但这将是故事的一个很好的结局。)

答案 15 :(得分:12)

我在控制台游戏中遇到了一个错误,只有在你打了一场并且赢得了一场漫长的boss战之后才发生,然后在5场比赛中只有一次。当它被触发时,它会让硬件100%楔入并无法通话到外面的世界。

这是我见过的最害怕的虫子;修改,自动化,检测或调试boss-battle会隐藏bug(当然我必须做10-20次运行来确定bug已隐藏)。

最后我通过反复阅读代码2-3天找到了问题(缓存/ DMA /中断竞争的事情)。

答案 16 :(得分:9)

想到的两个最棘手的错误都是在同一类型的软件中,只有一个在基于Web的版本中,一个在Windows版本中。

本产品是平面图查看器/编辑器。基于Web的版本有一个flash前端,可以将数据作为SVG加载。现在,这工作正常,只有有时浏览器会挂起。仅在几张图纸上,并且只有当你将鼠标摆动在绘图上一点时间时才会这样。我将问题缩小到单个绘图层,包含1.5 MB的SVG数据。如果我只采用了数据的子部分,任何子部分,则不会发生挂起。最终我突然意识到问题可能是文件中有几个不同的部分组合导致了这个bug。果然,在随机删除图层的各个部分并测试错误之后,我发现了令人讨厌的绘图语句组合。我在SVG生成器中编写了一个变通方法,修复了这个bug而没有改变一行动作。

在Windows端的同一产品中,用Delphi编写,我们遇到了类似的问题。此处产品采用autocad DXF文件,将它们导入内部绘图格式,并在自定义绘图引擎中呈现它们。这个导入例程效率不高(它使用了很多子字符串复制),但它完成了工作。只有在这种情况下它不是。一个5兆字节的文件通常在20秒内导入,但在一个文件上耗时20分钟,因为内存占用量增加到1千兆字节或更多。起初它似乎是一个典型的内存泄漏,但内存泄漏工具报告它干净,手动代码检查也没有发现。问题原来是Delphi 5的内存分配器中的一个错误。在某些条件下,这个特定文件正在重新创建,它将容易出现严重的内存碎片。系统将继续尝试分配大字符串,并且无法将它们置于最高分配的内存块之上。集成新的内存分配库可以修复bug,而无需更改一行导入代码。

回想一下,最棘手的错误似乎是其修复涉及更改系统的不同部分而不是发生问题的错误。

答案 17 :(得分:9)

当客户的宠物小兔子在中途通过以太网线啃咬时。是。这很糟糕。

答案 18 :(得分:8)

在设备调试器上有一个非常糟糕的平台上有一个错误。 如果我们在代码中添加了printf ,我们会在设备上获得崩溃。然后它会在与printf的位置不同的位置崩溃。如果我们移动printf,崩溃将移动或消失。实际上,如果我们通过重新排序一些简单的语句来改变代码,那么崩溃就会发生在与我们改变的代码无关的地方。

事实证明,我们平台的重定位器中存在错误。重定位器初始化ZI部分并非零,而是使用重定位表来初始化值。所以每当重定位表在二进制文件中发生变化时,bug就会移动。所以简单地添加一个printf会改变重定位表的错误。

答案 19 :(得分:8)

当我在一家电脑商店工作时,这件事发生在我身上。

有一天,有一位顾客来到商店,并告诉我们他的全新电脑在晚上和晚上工作正常,但在中午或早上根本不起作用。 麻烦的是鼠标指针在那时没有移动。

我们做的第一件事是改变他的鼠标,但问题并没有解决。当然,两个老鼠都没有过错地在商店工作。

经过多次尝试,我们发现问题出在该特定品牌和鼠标型号上。 客户工作站靠近一个非常大的窗户,在中午,鼠标在阳光直射下。 它的塑料很薄,在这种情况下,它变得半透明,防止阳光照射机电工作轮:|

答案 20 :(得分:7)

我的团队继承了基于CGI的多线程C ++ Web应用程序。主要平台是Windows;一个遥远的二级平台是带有Posix线程的Solaris。出于某种原因,Solaris上的稳定性是一场灾难。我们有不同的人在一年多的时间里关闭这个问题,一直关闭(主要是关闭),而我们的销售人员成功地推动了Windows版本。

症状是可怜的稳定性:各种各样的系统崩溃,几乎没有押韵或理由。该应用程序使用Corba和本土协议。一位开发人员甚至将整个Corba子系统移除作为一种绝望的措施:没有运气。

最后,一位资深的原创开发人员大肆想知道一个想法。我们查看了它并最终发现了问题:在Solaris上,有一个编译时(或运行时?)参数来调整可执行文件的堆栈大小。设置不正确:太小了。因此,该应用程序的堆栈和打印堆栈痕迹已经耗尽,这些痕迹是完全红色的鲱鱼。

这是一场真正的噩梦。

经验教训:

  • 头脑风暴,头脑风暴,头脑风暴
  • 如果在不同的,被忽视的平台上出现问题,那么它可能是环境平台的一个属性
  • 注意离开团队的开发人员转移的问题。如果可能,请以个人身份联系以前的人员以获取信息和背景信息。恳求,请求,达成协议。必须不惜一切代价减少经验损失。

答案 21 :(得分:7)

Adam Liss上面谈到我们所做的项目的消息,让我想起了一个我必须处理的有趣错误。实际上,这不是一个错误,但我们会在一分钟内完成。

应用程序的执行摘要,以防您尚未看到Adam消息:销售人员自动化软件......在笔记本电脑上......他们拨打的那天结束......与母亲数据库同步。< / p>

一位用户抱怨每次他试图拨入时,应用程序都会崩溃。客户支持人员经历了所有他们通常的电话诊断技巧,他们什么都没找到。所以,他们不得不放弃到最终目标:让用户FedEx将笔记本电脑送到我们的办公室。 (这是一个非常大的问题,因为每台笔记本电脑的本地数据库都是为用户定制的,因此必须准备一台新的笔记本电脑,运送给用户供他在我们处理原件时使用,然后我们不得不换回来让他最终在第一台原始笔记本电脑上同步数据。)

因此,当笔记本电脑到达时,我可以找出问题所在。现在,同步包括将电话线连接到内部调制解调器,转到我们应用的“通信”页面,然后从下拉列表中选择一个电话号码(预先选择使用的最后一个号码)。 DDL中的数字是定制的一部分,基本上是办公室的数量,以“+1”为前缀的办公室的数量,以及以“9 ,,,”为前缀的办公室的数量。从酒店打电话等。

所以,我点击“COMM”图标,然后按回车键。它拨入,它连接到调制解调器 - 然后立即崩溃。我累了几次。 100%的可重复性。

因此,笔记本电脑和笔记本电脑之间的数据范围很大。电话线,看着穿过线路的数据。它看起来很奇怪......最奇怪的部分是我可以阅读它!

用户显然想要使用他的笔记本电脑拨入本地BBS系统,因此,更改应用程序的配置以使用BBS的电话号码而不是公司的电话号码。我们的应用程序期待我们的专有二进制协议 - 不长的ASCII文本流。缓冲区溢出 - KaBoom!

在更改电话号码后立即拨打问题的事实可能会让普通用户知道这是问题的原因,但是这个家伙从未提及过它。 / p>

我修复了电话号码,并将其发回给支持团队,并附上一张纸条,选择了“本周的骨头用户”。 (*)


(*)OkOkOk ......这个家伙的孩子实际上发生了很大的事情,看到他的父亲每晚都拨打电话,想知道你是如何拨打BBS的,并在他有时更改了电话号码独自一人带着笔记本电脑回家。当它崩溃时,他不想承认他触摸了笔记本电脑,更不用说打破了它;所以他只是把它拿走了,并没有告诉任何人。

答案 22 :(得分:6)

这是在我的毕业论文中。我正在编写一个程序,用FORTRAN模拟高强度激光对氦原子的影响。

一次测试运行如下:

  • 使用程序1计算初始量子态,大约2小时。
  • 对第一步的数据进行主模拟,对于最简单的情况,大约需要20到50个小时。
  • 然后用第三个程序分析输出,以获得有意义的值,如能量,tork,动量

这些应该总是不变的,但事实并非如此。他们做了各种奇怪的事情。

经过两周的调试后,我对日志记录进行了狂暴,并在模拟的每个步骤中记录了每个变量,包括常量。

这样我发现我写了一个数组的结尾,改变了一个常量

一位朋友说他曾经因为这样的错误改变了文字2。

答案 23 :(得分:5)

基本上,涉及线程的任何事情。

我曾在一家公司担任过职务,其中我有一个可疑的区别,就是成为唯一能够通过线程调试讨厌问题的人之一。惊恐的事件。在允许编写线程代码之前,您必须获得某种认证。

答案 24 :(得分:5)

我的第一份“真正的”工作是为一家编写客户 - 服务器销售人员自动化软件的公司工作。我们的客户在他们的(15磅)笔记本电脑上运行客户端应用程序,并在一天结束时拨打我们的unix服务器以与Mother数据库同步。在一系列投诉之后,我们发现在认证过程中,一开始就有大量的电话掉线。

经过数周的调试后,我们发现如果来自服务器的getty进程回复了传入呼叫始终失败,该进程ID包含偶数,紧接着是9。身份验证是一个自制程序,依赖于PID的8个字符的字符串表示;一个错误导致一个违规的PID崩溃getty,后者用一个新的PID重新生成。第二次或第三次通话通常会找到一个可接受的PID,并且自动重拨使得客户无需进行干预,因此在电话账单在月底到达之前不会被视为重大问题。

“修复”(ahem)是将PID转换为表示 octal 中的值的字符串而不是十进制,这使得无法包含9并且无法解决根本问题。< / p>

答案 25 :(得分:5)

我花了几个小时来调试一些最终可以修复的东西,只有几个字符。

一些不同的例子:

  1. 当流中的裁剪值实际上完全有效时,ffmpeg有这种令人讨厌的习惯,即产生关于“脑热切割”的警告(指的是流内裁剪值> = 16的情况)。我通过添加三个字符来修复它:“h-&gt;”。

  2. x264有一个错误,在极少数情况下(百万帧中的一个)有某些选项会产生一个完全错误颜色的随机块。我通过在代码中的两个位置添加字母“O”来修复错误。原来我在之前的提交中错误地使用了#define的名称。

答案 26 :(得分:5)

我在高中时听说过一个经典的错误;如果你坐在前面的椅子上,你只能登录的终端。 (如果你站着,它会拒绝你的密码。)

它对大多数人来说非常可靠;你可以坐在椅子上,登录,注销......但如果你站起来,你每次都会被拒绝。

最终事实证明有些混蛋更换了键盘上的几个相邻按键,E / R和C / V IIRC,当你坐下时,你触摸键入并进入,但当你站着,你有狩猎'啄,所以你看了一下这些不合适的标签并且失败了。

答案 27 :(得分:5)

我的第一个多线程程序出现死锁!

找到它非常困难,因为它发生在线程池中。有时池中的线程会死锁,但其他线程仍然可以工作。由于池的大小比需要的大得多,所以花了一两个星期注意到第一个症状:应用程序完全挂起。

答案 28 :(得分:4)

我们的网络接口,一个支持DMA的ATM卡,偶尔会在收到的数据包中提供损坏的数据。该AAL5 CRC已签出是正确的,当数据包进来脱丝,但数据DMAD内存是不正确的。 TCP校验和通常会捕获它,但是在令人兴奋的ATM时代,人们热衷于直接在AAL5上运行本机应用程序,完全不需要TCP / IP。我们最终注意到腐败只发生在供应商工作站的某些型号上(谁将保持无名),而不是其他型号。

通过计算驱动程序软件中的CRC,我们能够检测到损坏的数据包,但代价是巨大的性能损失。在尝试调试时,我们注意到如果我们只是将数据包存储了一段时间并稍后再回过头来查看它,那么数据损坏就会神奇地自愈。数据包内容没问题,如果驱动程序第二次计算CRC,它会检查确定。

我们在发货CPU的数据缓存中发现了一个错误。此处理器中的缓存与DMA不一致,要求软件在适当的时间显式刷新它。该错误是有时缓存在被告知时实际上没有刷新其内容。

答案 29 :(得分:4)

虽然我不记得一个特定的实例,但最棘手的类别是那些只在系统运行了几个小时或几天之后才会出现的错误,当它崩溃时,几乎没有留下导致崩溃的痕迹。让他们特别糟糕的是,无论你认为自己如何理解原因,并采用适当的解决办法来解决问题,你都需要等待几个小时或几天才能对你有所信心。真的把它钉了出来。

答案 30 :(得分:3)

这是一次访问冲突崩溃。从崩溃转储我只能弄清楚调用堆栈上的参数已损坏。
原因was this code

n = strlen(p->s) - 1;
if (p->s[n] == '\n')
   p->s[n] = '\0';    

如果字符串长度为0,并且上面堆栈上的参数恰好位于地址0x0Axxxxxxx上,则==&gt; 堆栈损坏
幸运的是,此代码足够接近实际崩溃位置,因此浏览(丑陋)源代码是查找culrpit的方法

答案 31 :(得分:3)

由于灵感的闪现,这并不需要太长时间来追踪,但仍然有点奇怪。小型应用程序,仅供IT部门的其他人使用。它依次连接到域中的所有桌面PC。许多都被关闭,连接需要AGES超时,所以它在线程池上运行。它只扫描AD并将数千个工作项排队到线程池。一切正常。几年后,我正在与另一位真正使用此应用程序的员工交谈,他提到这使得PC无法使用。当它正在运行试图打开网页或浏览网络驱动器需要几分钟,或者只是永远不会发生 问题原来是XP的半开tcp限制。最初的PC是双处理器,所以.NET为池分配50(或100,不确定)线程,没问题。现在我们有双处理器双核,我们现在在线程池中拥有的线程多于半开放连接,因此在应用程序运行时,其他网络活动变得无法实现。

它现在已修复,它在尝试连接它们之前ping机器,因此超时时间要短得多,并且使用少量固定线程来完成实际工作。

答案 32 :(得分:3)

设计了一个实时多线程(颤抖)系统,该系统可以从多个网络监控摄像机中查看图像,并在图像上进行各种魔术处理。

这个漏洞只是让系统崩溃,一些关键部分被误导了。我不知道如何直接触发故障,但不得不等待它发生,大约三到四天一次(赔率:在300 fps的15000000左右,大约1)。

我必须准备好一切,调试输出消息弄脏代码,跟踪工具,远程调试工具在相机上,列表继续。然后我只需要等待两到三天,并希望能够找到所有信息来找到失败的互斥锁或其他什么。在我追踪它之前,它花了四个星期,四个星期!再跑一次,我就打破了客户的最后期限..

答案 33 :(得分:3)

我在一所大型社区学院工作,去年我们从Blackboard转到了Moodle。 Moodle使用“课程”和“团体”的命名法。例如,课程可能是微观经济学ECO-150,我们称之为小组(OL1,OL2,01,14,W09为例)。

无论如何,我们是原始的。我们甚至没有LDAP。一切都是文本文件,Excel电子表格和 GD 微软Access数据库。我的工作是创建一个Web应用程序,它将上述所有内容作为输入,并生成更多的文本文件,然后上传到Moodle,以创建课程,课程和用户组,并将用户放入课程和组。整个设置是拜占庭式的,必须按顺序完成大约17个单独的步骤。但事情有效并且取代了之前在学期最忙碌的时间里花了好几天的过程。

但是有一个问题。有时我们得到了我称之为“疯狂群体”的东西。因此,不是创建一个包含4组20名学生的课程,而是创建一个包含80组,每组1名学生的课程。最糟糕的是,一旦创建了组,就无法以编程方式进入cpanel(我无权访问)来删除组。这是一个手动过程,大约需要5次按钮。因此,每次创建Crazy Groups课程时,我都要删除课程,如果教师已经开始在课程中添加内容,那么这是优选但不是一个选项,或者我不得不重复按照相同的模式花一个小时:选择组,显示组,编辑组,删除组,确定要删除组吗?对于godsake是的!

除非你手动打开每个课程并查看(有数百个课程)或者直到你收到投诉,否则无法知道疯狂的团体是否已经发生过。 Crazy Groups 似乎随机发生,Google和Moodle论坛没有任何帮助,似乎其他所有人都使用这个名为LDAP或REAL数据库的东西,所以他们从未遇到过这个问题。

最后,在我不知道有多少调查和更多时间删除疯狂的群体之后,我想要承认我已经弄清楚了。这是Moodle中的一个错误而不是我的代码!这给了我一点乐趣。您看到创建组的方法只是尝试将某人注册到该组中,如果该组尚未存在,则Moodle会创建该组。这适用于名为OL1或W12甚至SugarCandyMountain的团队,但是如果你试图创建一个名为01或14的组,那就是疯狂的团体会发生的时候。 Moodle没有正确地将数字比作字符串。无论一个课程中有多少个名为01的小组,它总会认为该小组尚不存在,因此会创建它。这就是你最终得到80个团体的方法,每人只有1个人。

对我的发现感到自豪我去了Moodle论坛并发布了我的调查结果以及随意重现问题的步骤。那是大约一年前的事情,据我所知,问题仍然存在于Moodle内部,没有人似乎有动力修复它,因为除了我们原语之外没有人使用文本文件注册。我的解决方案,只是为了确保我们所有的组名包含至少一个非数字字符。疯狂的团体至少对我们来说已经一去不复返了,但我觉得那个在蒙古外国社区大学工作的人只是上了一个学期的课程而且即将有一个粗鲁的觉醒。至少这次谷歌可以帮助他,因为我已经在网络空间的潮流中将这条信息写在了一个瓶子里。

答案 34 :(得分:3)

在回到普渡大学的CS435中,我们必须为最终项目编写光线跟踪器。我生产的所有东西都有强烈的橙色色调,但我可以看到我场景中的每一个物体。我终于放弃并按原样提交了它,并让教授查看我的代码以找到错误,当他找不到它时,我花了大部分时间去挖掘找到错误的地方。

深埋在代码中,作为颜色计算功能的一部分,我终于意识到我正在划分一个int并将其传递给预期浮点值的OpenGL函数。其中一个颜色成分在大部分场景中都足够低,它会向下舍入到0,从而产生橙色色调。在一个地方(分割前)将它投射到一个浮子上来修复这个错误。

请务必检查您的输入和预期类型。

答案 35 :(得分:3)

我遇到的最棘手的错误就是我自己提出的一个错误 - 我作为大型电信公司的测试员签约,测试另一家公司的产品。几年后,我和另一家公司签了合同,他们给我的第一件事就是我自己提出的错误。

在嵌入式操作系统中使用6809汇编程序和BCPL编写的内核竞争条件。调试环境由一个写入串行设备的特殊printf组成;这个设置中没有花哨的IDE东西。

花了很长时间才解决这个问题但是当我最终解决它时,这是一个巨大的满足感。

答案 36 :(得分:2)

在我正在进行的游戏中,特定的精灵在发布模式下不再显示,但在调试模式下工作正常,并且仅在一个特定版本中工作。另一位程序员试图找到这个bug 2天,然后去度假。它最终在我的肩膀上试图在发布前5小时找到它。

由于Debug构建工作,我不得不使用发布版本进行调试。 Visual Studio支持Release版本中的一些调试,但您不能依赖调试器告诉您的所有内容(特别是我们使用的积极优化设置)。因此,我不得不单步执行半个代码清单和一半汇编程序列表,有时直接在十六进制转储中查找对象,而不是在格式良好的调试器视图中。

花了一段时间确保正在进行所有正确的绘制调用之后,我发现精灵的材质颜色不正确 - 它应该是完全不透明的橙色,而是设置为黑色并且完全透明。从我们的EditionManager类中驻留在const数组中的调色板中抓取颜色。它最初设置为正确的橙色,但是当从精灵绘图代码中检索到实际颜色时,它再次是透明的黑色。我设置了一个内存断点,它在EditionManager构造函数中触发。写入不同的数组会导致调色板数组中的值发生变化。

事实证明,另一位程序员改变了系统的基本枚举:

enum {
    EDITION_A = 0,
    EDITION_B,
    //EDITION_DEMO,
    EDITION_MAX,

    EDITION_DEMO,
};

他将EDITION_DEMO放在EDITION_MAX之后,并且正在写入的数组已使用EDITION_DEMO编入索引,因此它会溢出到调色板中并在那里设置错误的值。然而,由于版本号不能再改变(它们被用于二进制传输),我无法更改枚举。因此,我最终在枚举中创建了一个EDITION_REAL_MAX条目,并将其用作数组大小。

答案 37 :(得分:2)

在调试中运行的多线程应用程序很好,但是一旦你在发布版本中运行它会因为时间略有不同而出错。即使将Console.WriteLine调用添加到产品基本调试outpit也会导致其工作时间发生变化,并且不会显示问题。工具一周,找到并修复需要更改的几行代码。

答案 38 :(得分:2)

就在互联网流行之前,我们正在开发一个基于调制解调器的家庭银行应用程序(北美第一个)。

发布前三天,我们(几乎)按计划进行,并计划用剩余的时间对系统进行彻底的测试。我们有一个测试计划,列表中的下一个是调制解调器通信。

就在那时,我们的客户急于想要最后一分钟的功能升级。当然,我完全反对这一点,但我被推翻了。我们把午夜的油烧了三天,添加了愚蠢的东西,并在发布日期之前完成了工作。我们制定了截止日期,并向客户提供了2000多张软盘。

发布后的第二天,我回到了测试计划,并重新开始测试调制解调器通信模块。令我惊讶的是,我发现调制解调器会随机连接失败。就在那时,我们的手机开始响起,愤怒的客户无法使用他们的应用程序。

经过大量的牙齿和拔毛之后,我将问题追溯到串口初始化。一位初级程序员已经注释掉了对其中一个控制寄存器的写入。寄存器保持未初始化状态,并且有大约10%的可能性包含无效值 - 取决于用户的配置,以及他之前运行的应用程序。

当被问到这个问题时,程序员声称它可以在他的机器上运行。

所以我们不得不重新烧掉那些2000+以上的软盘,并追踪每一位客户以回忆它们。这不是一件有趣的事情,特别是对于已经筋疲力尽的团队。

我们对那一个大受欢迎。我们的客户声称,因为这是我们的错误,我们应该承担召回的费用。我们下一个版本的时间表已经提前一个月了。我们与客户的关系受到了损害。

如今,我对最后一分钟的功能添加不太灵活,我尝试与我的团队进行更好的沟通。

答案 39 :(得分:1)

当我第一次来到我工作的公司时,我做了很多CPR来学习产品。

这种用HC11组件编写的嵌入式产品具有每八小时发生一次的功能。结果是在检查计数器的代码期间递减值的中断。在代码周围打了一些CLI / STI,很好。我通过黑客攻击事件来追踪它,每秒发生两次,而不是每8小时发生一次。

我从中学到的教训是,在调试不经常失败的代码时,我应该首先检查中断使用的变量。

答案 40 :(得分:1)

我曾经在.NET应用程序中遇到一个错误,导致CLR崩溃 - 是的,CLR只会以非零结果退出并且没有调试信息。

我用控制台跟踪消息试图找出问题所在的位置(启动时会发生错误)并最终找到导致问题的几行。我尝试隔离这个问题,但每次我做完孤立的情况都会有效!

最后我更改了代码:

int value = obj.CalculateSomething();

int value;
value = obj.CalculateSomething();

不要问我为什么,但这很有用。

答案 41 :(得分:1)

我目前正在上大学,我遇到的最难的错误来自那里的编程课。在前两个学期,我们只是编写了自己的代码。但是对于第三学期,教授和TA会编写一半的代码,我们写的是另一半。这是为了帮助我们学习阅读代码。

我们在那个学期的第一个任务是编写一个模拟DNA基因分裂的程序。基本上,我们只需要在较大的子串中找到子串并处理结果。显然,教授和TA都在那个星期忙着给我们他们的一半代码而没有完成他们自己的完整实现。他们没有时间写另一半作为解决方案。他们的一半将编译,但没有完整的解决方案编码,他们没有办法测试它。 我们被告知不要改变教授代码。班上的每个人都有完全相同的错误,但我们仍然认为我们都犯了同样的错误。

该程序吞噬了数十亿字节的内存然后耗尽并崩溃。我们(学生们)都假设我们的一半代码必须有一些模糊的内存泄漏。班上的每个人都在搜索代码两周,然后一遍又一遍地通过调试器运行它。我们的输入文件是一个5.7 MB的字符串,我们在其中找到了数百个子字符串并存储它们。教授/ TA的代码使用了这个。

myString = myString.substr(0,pos);

看到问题?将字符串变量分配给自己的子字符串时,不会重新分配内存。这是一个没有人(甚至教授或TA)都不知道的信息。所以myString只有5.7 MB的分配内存,只能容纳几个字节的实际数据。这重复了数百次;因此大量的内存使用。我花了两个星期来解决这个问题。我花了第一周检查自己的代码是否有内存泄漏。在我的沮丧中,我终于得出结论,教授/ TA的一半必须有泄漏,所以我花了第二周检查他们的代码。但即便如此,我花了很长时间才找到,因为这在技术上并不是泄漏。所有分配最终都被释放,当我们的输入数据只有十几千字节时,程序运行正常。我找到它的唯一原因是因为我发送了心理疯狂并决定分析每一个最后一个变量;即使是暂时扔掉的东西。我也花了很多时间检查字符串实际有多少个字符,而不是分配了多少字符。我假设字符串类正在处理这个问题。这是一个解决方案,一个单行更改,修复了数周的挫折,并为我找到了一个A,用于查找/修复教师的代码。

myString.substr(0,pos).swap(myString);

交换方法会强制重新分配。

答案 42 :(得分:1)

我修复过的最棘手的错误实际上是在我职业生涯的早期阶段。我正在研究一个使用GEC 2050配备共享内存的电站的实时系统。

2050 RTOS有一个主调度表,每个进程包含一个插槽,其内容可以是非活动进程的add 1,X指令或可执行进程的跳转。在X设置为零的情况下执行此表意味着第一个可运行的进程自动进入,X寄存器是进程号。设计这个的人显然觉得他很聪明!

2050架构还具有安全功能,其中无法识别的操作码始终导致停止。由于2050年有一个完整的前面板,你可以用它来尝试找出崩溃的东西。由于X寄存器始终保持当前进程ID,因此通常非常简单。

没有内存分段或保护,因此进程完全有可能破坏当前内存中的任何其他进程或系统区域中的任何进程。

到目前为止,这个时代(70年代后期)非常一致。

由于此特定系统在两个CPU之间具有共享内存,因此系统配置将系统表放置在共享内存中,以允许一个CPU启动和停止另一个CPU中的进程,而无需通过任何namby pamby安全接口。

不幸的是,这也让一个CPU的狂野进程破坏了另一个CPU的表,因此一个CPU可能会很快崩溃另一个CPU。如果发生这种情况,在崩溃的CPU中运行的内容与实际故障完全没有关系。与此同时,另一个CPU很乐意继续进行,因此没有办法判断它是否导致了这个问题。

毋庸置疑,这提供了一些难以解决的问题!

在一点点头发撕裂之后,我最终向O / S写了一个相当大的补丁,它在调度程序表中查找了另一个CPU的损坏,并使正在运行的CPU崩溃。这被连接到一个常规中断,所以虽然没有完全同步,但至少它很有可能捕捉到违规的过程。

这有助于我清除相当多的互CPU问题......

答案 43 :(得分:1)

当一个特定用户访问某个库存功能时,基于旧数据库的应用程序(只有部分源可用)崩溃。它适用于所有其他用户。用户档案对吗?不。 以其他用户(即使是管理员)身份登录时,同一用户也遇到了同样的问题。

电脑问题?不。相同的用户,不同的PC(在她的登录或任何其他登录下)仍然崩溃。

问题:当登录程序时显示版权启动画面,可以通过单击“X”关闭窗口或按任意键来关闭。登录此用户时,始终单击“X”,其他用户始终按下某个键。这导致内存泄漏,但仅在访问库存查找时才会发生。

修复:不要点击X。

答案 44 :(得分:1)

一个盒子在一个大客户的网站上崩溃,我们不得不通过WebX会话连接到IT人员的计算机,该计算机连接到我们的盒子。我捅了大约一个小时,抓住堆栈跟踪,注册转储,统计信息,计数器,并转储似乎相关的内存部分。

他们的IT人员随后通过电子邮件向我发送了会话记录,我开始工作了。

几个小时后,我将其追溯到一系列结构,其中包含数据包元数据,然后是数据包数据。其中一个数据包的元数据已损坏,看起来它已被几个字节的数据包数据覆盖。 Bugzilla没有类似的记录。

深入研究代码,我检查了所有明显的事情。将数据包数据复制到缓冲区的代码非常细致,不超过其界限:缓冲区是接口的MTU大小,复制例程检查数据是否超过MTU大小。我的内存转储允许我验证,是的,当崩溃发生时,foo-&gt; bar确实是4。什么都没有加起来。以一种应该导致问题的方式没有错。在下一个标题中看起来像16字节的数据包数据。

几天后,我开始检查任何我能想到的东西。

我注意到数据缓冲区的长度实际上是正确的。也就是说,从数据开始到数据结束的字节数是MTU,即使下一个标题是从MTU-16开始。

当这些结构被malloc'd时,指向每个元素的指针放在一个数组中,我就抛弃了那个数组。我开始测量这些指针之间的距离。 6888 ... 6888 ... 6888 ... 6872 ... 6904 ... 6880 ... 6880 ...

等等,什么?

我开始查看两个结构中的内部指针和偏移量。一切都加起来了。它只是看起来像我的一个糟糕的结构 - 一个被部分破坏的结构 - 在内存中只有16个字节。

分配例程将这些人作为一个块进行malloc,然后将它们分成一个循环:

   for (i = 0; i < NUM_ELEMS; i++) {
      array[i] = &head[i*sizeof(foo)];
   }

(允许对齐等)。

当数组填满时,我的损坏指针的值必须被读为0x8a112 8 ac而不是0x8a112 9 ac。

我得出的结论是,我在分配期间一直是1位内存错误的受害者(我知道,我知道!我也不相信,但我们之前在这个硬件上看过它们 - - 读取为0x00800000的NULL值)。在任何情况下,我设法说服我的老板和同事没有其他合理的解释,我的解释正好解释了我们所看到的。

所以,框RMA'd。

答案 45 :(得分:1)

可能看起来很有趣但是当我学习的时候我花了整整一个下午试图弄清楚为什么if语句总是评估为真我使用=而不是==:在另一台计算机上重写了两次:)

答案 46 :(得分:1)

在Python中,我有一个线程做这样的事情:

while True:
    with some_mutex:
        ...
        clock.tick(60)

clock.tick(60)暂停该线程,使其每秒运行不超过60次。 问题是大多数时候程序只显示黑屏。如果我让它运行一段时间,它终于显示了游戏画面。

这是因为线程正在执行暂停,同时保持互斥锁。因此很少让其他线程获得互斥锁。这看起来似乎很明显,但我花了两天时间来弄明白。解决方案只是删除缩进级别:

while True:
    with some_mutex:
        ...

    clock.tick(60)

答案 47 :(得分:1)

Oracle的OracleDecimal类的ToString方法(P /调用相同功能的本机版本)和垃圾收集器之间的竞争,这是由于缺少GC.KeepAlive调用导致OracleDecimal.ToString()返回基本上任意的垃圾邮件在调用结束之前,它的堆空间恰好被覆盖了。

我写了一篇详细的错误报告但从未收到回复,因为我知道这仍然存在。我甚至有一个测试工具除了创建数字1的新OracleDecimal表示,在它们上面调用ToString,并将结果与​​“1”进行比较之外什么也没做。每十万次左右,它会以疯狂的胡言乱语(大数字,负数,甚至是字母数字的垃圾串)失败。

请注意你的P / Invoke电话!只要实例方法已完成使用this引用,.NET垃圾收集器在对该实例上的实例方法的调用仍处于挂起状态时收集您的实例是合法的。

对于像这样的东西,

Reflector绝对是救星。

答案 48 :(得分:1)

当程序员输出到日志“常规错误!”时,最棘手的错误就是。在查看代码之后,它随处散布着“General Error!”文本。试着把那个打倒。

至少写一个宏来输出__LINE__或__FUNCTION__对于添加到调试输出会更有帮助。

答案 49 :(得分:1)

不确定这是最难的,但几年前我有一个Java程序,它使用XMLEncoder来保存/加载特定的类。由于某种原因,班级工作不正常。我做了一个简单的二进制搜索错误,并发现错误发生在一个函数调用之后但在另一个调用之前,这应该是不可能的。 2个小时后我还没弄明白,虽然我休息一下(然后离开)的那一刻我意识到了这个问题。原来,XMLEncoder正在创建一个默认构造的类实例,而不是让类和对类的引用都引用同一个对象。所以,虽然我认为两个函数调用同时在特定类的同一实例的成员上,其中一个实际上是在默认构造的副本上。

很难找到,因为我知道他们都是对同一个班级的引用。

答案 50 :(得分:1)

Java Server应用程序中的死锁。但不是一个有两个线程的简单死锁。我找到了涉及八个线程的死锁。线程1等待线程2等待线程3等,最后线程8等待线程1。

我花了大约一整天的时间来了解发生了什么,然后花了15分钟来修复它。我使用eclipse监视大约40个线程,直到我发现死锁。

答案 51 :(得分:1)

我有一次自定义同步程序的错误。它使用文件/文件夹的日期/时间戳来比较修改的内容,以便将数据从闪存密钥同步到Windows中的网络共享,并在其中内置一些额外的完整性和业务逻辑。

有一天,一位运营商报告他的同步正在进行中......在查看日志之后,由于某种原因,软件认为棒(或服务器)上的每个文件都比它应该的旧3个小时,令人耳目一新所有8演出的数据!我使用的是UTC,这怎么可能呢?

事实证明,这个特定的运营商确实将他的时区设置为太平洋时间而不是东部,导致问题,但它不应该有,因为所有的代码都使用UTC - 好神,它会是什么?!它在我的本地系统上进行测试时起作用了...是什么给出了?

此时,我们要求所有运营商确保他们的笔记本电脑在同步之前设置为东部时间,并且在我们有更多时间进行调查之前,错误一直停留在队列中。

然后,10月来到了BOOM!夏令时!有没有搞错!?现在每个人都在抱怨同步是永远的!不得不修好,而且快!

我通过修改测试用例来追踪它而不是关闭我的本地硬盘驱动器,当然,它失败了...... phew,必须记忆棒的东西 - 等一下,是格式化的FAT32 ... 啊哈! FAT32在记录文件的时间戳时使用本地时间!

http://msdn.microsoft.com/en-us/library/ms724290(VS.85).aspx

因此,软件被重写,以便在写入FAT32媒体时,我们以编程方式将其设置为UTC ...

答案 52 :(得分:1)

很久以前,我使用C和一个(基于字符的)表单库编写了面向对象的语言;每个表单都是一个对象,表单可以包含子表单,依此类推。使用此编写的复杂开票应用程序可以正常工作大约20分钟,然后随机出现的垃圾字符会不时出现在屏幕上。使用该应用程序几分钟后,机器将重新启动,挂起或发生激烈的事情。

这被证明是由于消息处理引擎中的错误委派导致的错误解除分配;当我们用完超类时,错误路由的消息被委托给包含树,有时父对象将具有相同名称的方法,因此它看起来大部分时间都可以工作。剩下的时间它会在错误的上下文中释放一个小缓冲区(大约8个字节)。错误地解除分配的指针实际上是中间计数器用于另一个操作的死存储器,因此其值往往会在一段时间后收敛于零。

是的,坏指针会在通往零页面的过程中穿过屏幕的内存映射区域,最终覆盖了一个中断向量并杀死了PC

这是现代调试工具之前的方法,所以弄清楚发生了什么需要几个星期......

答案 53 :(得分:1)

如果安装了应用程序的目录路径不包含至少一个空格,并且XPO检查的数据字典不是100%正确,则DevExpress XPO与Oracle数据库进行快速崩溃(如:程序以静默方式退出)在数据库中。

问题描述为here

我可以告诉你:我是这个&gt;&lt;当我们想出如何规避问题时,我们会哭得很近。我仍然不知道问题的实际,真实,原因是什么,但我们的产品在未来的版本中不会支持Oracle,所以我实际上不再给....了。

答案 54 :(得分:1)

不是我的,但前一个工作地点的同事花了3天时间调试他的JavaScript popout编辑器控件(这是很久以前,在框架的乐趣之前),却发现它缺少一个分号中间有一个巨大的核心文件。

我们称之为“世界上最昂贵的分号”,但我确信历史上的情况要差得多!

答案 55 :(得分:1)

有一个代码通过在当前年份加1并将日期和月份保持为相同,将当前日期的一些到期日期加上一年。 2008年2月29日这个失败的大时间因为数据库拒绝接受2009年2月29日!

不知道这是否有资格成为“强硬”,但这是一个奇怪的代码,当然会立即重写!

答案 56 :(得分:1)

这有点偏离主题(这就是为什么我把它作为社区)。

但Ellen Ullman的The Bug是关于这个主题的奇妙小说。

答案 57 :(得分:0)

我遇到的最棘手的错误不是由我造成的,虽然它导致我的代码崩溃! 这是DOS上的TurboPascal。 TurboPascal编译器编译器有一个小的升级,突然间我的二进制文件开始崩溃。 原来,在新版本中,内存仅从段边界开始分配。当然我的程序从未检查过这些东西,因为为什么?程序员怎么会知道这些事情?旧的compuserve特殊兴趣小组的某个人发布了这个线索和解决方法:

由于段长度为4个字,因此修复程序总是使用mod(4)来计算要分配的内存大小。

答案 58 :(得分:0)

我用以下代码修复了某人的错误:

private void foo(Bar bar) {
    bar = new Bar();
    bar.setXXX(yyy);
}

他预计bar将在foo之外更改!

答案 59 :(得分:0)

用两个词来说:内存泄漏

答案 60 :(得分:0)

Unexplained SQL Server Timeouts and Intermittent Blocking

我们遇到了一个问题,我们的用户显然没有理由超时。我对SQL Server进行了一段时间的监控,发现每隔一段时间就会有很多阻塞。所以我需要找到原因并解决它。

如果发生了阻塞,那么在存储的proc调用链中某处必须有独占锁...正确?

我走过了被调用的存储过程的完整列表,以及所有后续存储的过程,函数和视图。有时这种层次结构很深,甚至是递归的。

我正在寻找任何UPDATE或INSERT语句......没有任何(除了临时表只有存储过程的范围,所以他们没有计算。)

在进一步的研究中,我发现锁定是由以下原因造成的:

一个。如果使用SELECT INTO创建临时表,则SQL Sever会将锁定放在系统对象上。以下是我们的getUserPrivileges proc:

            --get all permissions for the specified user
            select   permissionLocationId,
                permissionId,
                siteNodeHierarchyPermissionId,
                contactDescr as contactName,
                l.locationId, description, siteNodeId, roleId
            into #tmpPLoc
            from vw_PermissionLocationUsers vplu
                inner join vw_ContactAllTypes vcat on vplu.contactId = vcat.contactId
                inner join Location l on vplu.locationId = l.locationId
            where  isSelected = 1 and
                contactStatusId = 1 and
                vplu.contactId = @contactId

每个页面请求都会调用getUserPrivileges proc(它位于基页中。)它没有像您期望的那样进行缓存。它看起来不像,但上面的SQL引用了FROM或JOIN子句中的23个表。这些表中都没有“with(nolock)”提示,因此需要更长的时间。如果我删除WHERE子句以了解所涉及的行数,它将返回159,710行并需要3到5秒才能运行(在服务器上没有其他人的几小时之后。)

因此,如果这个存储过程只能由于锁定而一次一个地运行,并且每个页面调用一次,并且它在select和temp的持续时间内保持系统表上的锁定表创建,您可以看到它可能如何影响整个应用程序的性能。

对此的修复将是: 1.使用会话级缓存,这样每个会话只调用一次。 2.使用标准Transact-SQL DDL语句将SELECT INTO替换为创建表的代码,然后使用INSERT INTO填充表。 3.将“with(nolock)”放在与此呼叫有关的所有内容上。

B中。如果存储的proc getUserPrivileges没有足够的问题,那么让我补充一下:它可能会在每次调用时重新编译。因此,SQL Server会在每次调用时获取COMPILE锁。

重新编译它的原因是因为创建了临时表,然后从中删除了很多行(如果传入了@locationId或@permissionLocationId)。这将导致存储的proc在后面的SELECT上重新编译(是的,在运行存储过程的过程中。)在其他过程中,我注意到了一个DECLARE CURSOR语句,其SELECT语句引用了一个临时表 - 这将强制执行重新编译。

有关重新编译的更多信息,请参阅: http://support.microsoft.com/kb/243586/en-us

对此的修复将是: 1.再一次,使用缓存命中这个存储过程的次数要少得多。 2.在创建表时,在WHERE子句中应用@locationId或@permissionLocationId过滤。 3.用表变量替换临时表 - 它们导致更少的重新编译。

如果事情没有像你期望的那样发挥作用,那么你可以花很多时间盯着某些东西而不必弄清楚什么是错的。

答案 61 :(得分:0)

我们在DOS提示符下运行了一个RMI服务器 有人“选择”了窗口 - 暂停了这个过程

修复很简单......按回车。

这是非常痛苦的一天......

答案 62 :(得分:0)

在设备调试器上有一个非常糟糕的平台上有一个错误。如果我们在代码中添加了printf,我们会在设备上崩溃。然后它会在与printf的位置不同的位置崩溃。如果我们移动了printf,崩溃将会移动或消失。实际上,如果我们通过重新排序一些简单的语句来改变代码,那么崩溃就会发生在与我们改变的代码无关的地方。

这看起来像是经典的Heisenbug。一旦你认出它,你就会立即去寻找未初始化的变量或堆叠边界垃圾。

答案 63 :(得分:0)

有几个我可以记得的,其中大部分是由我引起的:)。几乎其中一个需要大量的头部刮擦。

  1. 我是java项目(富客户端)的一部分,java代码用于在vanilla构建或新机器上运行良好而没有问题,但是当安装在演示笔记本电脑上时,它突然停止工作并开始抛出stackdump 。进一步调查表明,该代码依赖于与cygwin冲突的自定义DLL。这不是故事的结尾,我们应该把它安装在其他5个机器上并猜测是什么,在其中一台机器上它又崩溃了!这次罪魁祸首是jvm,我们给出的代码是使用Sun microsystems jdk构建的,机器有ibm的jvm。

  2. 我可以回忆起的另一个实例与自定义事件处理程序代码有关,代码经过单元测试和验证,最后当我删除了print()语句时,BOOM !!当我们调试时,代码运行完美地增加了我们的欠款。我不得不求助于禅修(在桌子上打个盹),并且发现可能有颞神经的肛门!我们委托的事件甚至在条件设定之前触发了该功能,印刷声明&amp;调试模式提供了足够的时间来设置条件,因此正常工作。松了一口气,一些重构解决了这个问题。

  3. 有一天我决定实现Clonable接口所需的一些域对象,事情很好。几周后,我们观察到应用程序开始表现得很糟糕。你猜怎么着?我们将这些浅拷贝添加到集合类中,而remove()方法实际上并没有正确地清除内容(由于重复的引用指向同一个对象)。这导致了一些严肃的模型审查和一些凸起的眉毛。

答案 64 :(得分:0)

我曾经卸载过PHP。手动。通过一次移动修复了很多错误......

答案 65 :(得分:0)

Heisenbug,主要困难是没有意识到这根本不是我的错误。

问题是API接口。调用任何实际函数(与安装程序相反)都有很高的崩溃概率。单步执行该功能(在可能的范围内,它会遇到一个中断,你无法追踪到那一点 - 当你使用中断与系统通信时,它会回来)产生正确的输出,没有崩溃。 / p>

经过长时间的搜索,我做错了什么,我终于通过RTL例程来试图理解我做错了什么。我做错了是相信例程工作 - 所有被轰炸的例程都是用保护模式指针类型操纵实模式指针。除非实模式段值在保护模式下有效,否则就会出现这种情况。

然而,关于调试器操作程序的一些事情导致了单步执行时的正确操作,我从不打算弄明白为什么。

答案 66 :(得分:0)

多年前,我花了几天的时间尝试跟踪并修复dbx(AIX上基于文本的调试器)中的一个小错误。我不记得确切的错误。让我很难的是我使用已安装的dbx来调试我正在开发的dbx的开发版本。追踪我的位置非常困难。不止一次,我准备离开这一天并退出dbx两次(dev版本和安装版本)只是为了看到我仍在在dbx中运行,有时两个或更多级别“深”

-
BMB

答案 67 :(得分:0)

从服务加载的DLL中发生崩溃。 关闭系统触发。

该错误很容易修复,但找到它需要大约一周时间 - 而且很多挫折感。

答案 68 :(得分:0)

我使用的文本编辑控件中的堆内存冲突。经过几个月(...)寻找它,我发现解决方案与另一个程序员合作,同行调试问题。这个例子使我确信团队合作和敏捷的价值。在my blog

了解详情

答案 69 :(得分:0)

这是Rhino(Java中的Javascript解释器)中的一个小错误导致一个脚本失败。这很难,因为我对解释器的工作原理知之甚少,但为了另一个项目,我必须尽快跳到那里来修复bug。

首先我跟踪了Javascript中哪个调用失败了,所以我可以重现这个问题。我在调试模式中逐步完成了运行的解释器,最初很丢失,但是慢慢地学习它是如何工作的。 (阅读文档有点帮助。)我在我认为可能相关的点添加了printlns / logging。

我将一个正在运行的运行的(已清理的)日志文件与一个中断运行区分开来,以查看它们在什么时候开始发散。通过重新运行并添加大量断点,我找到了导致失败的事件链。在某处有一行代码,如果写得略有不同,就解决了问题! (这很简单,就像nextNode()应该返回null而不是IndexOutOfBounds。)

在那之后的两周,我意识到我的修复程序在某些其他情况下破坏了脚本,并且我改变了该行以适应所有情况。

我在一个陌生的环境中。所以我尝试了很多不同的东西,直到其中一个工作,或者至少有助于取得一些进展/理解。 做了需要一段时间,但我很高兴最终到达那里!

如果我现在再次这样做,我会寻找该项目的IRC频道(不仅是其邮件列表),提出一些礼貌问题并寻求指导。

答案 70 :(得分:0)

我无法想象他们是如何编码的: 您不能将IP地址127.0.0.1分配给环回适配器,因为它是环回设备的保留地址--Microsoft(r)WindowsXP PROFESSIONAL

答案 71 :(得分:0)

我有一段delphi代码,它运行了一个很长的处理程序来更新进度条。代码在16位Delphi 1中运行良好,但是当我们升级到delphi 2时,一个耗时2分钟的过程突然耗费了大约一个小时。

经过几周的例行程序分离后,事实证明这是更新导致问题的进度条的行,对于每次尝试我们使用table1.recordcount检查记录计数,在delphi 1中这工作正常但看起来似乎在delphi的后续版本中调用table.recordcount在dbase表上获取表的副本对记录进行计数并返回金额,在我们进度的每次尝试中调用它都会导致每次迭代都会从网络下载表并计算。解决方案是在处理开始之前对记录进行计数,并将数量存储在变量中。

找了很久才找到,但事实证明这么简单。

答案 72 :(得分:0)

用Turbo Pascal编写的GUI应用程序中令人讨厌的崩溃。在我发现之前三天,通过调试器中的单步执行,在机器代码级别,通过简单且明显正确的代码,我在调用堆栈上放置一个16位整数,用于期望32位的函数(或者一些这种不匹配)

现在我很明智,尽管现代编译器不再允许那种麻烦了。