《Effective Debugging:软件和系统调试的66个有效方法》——第17条:使故障更加突出

本节书摘来自华章计算机《Effective Debugging:软件和系统调试的66个有效方法》一书中的第2章,第17节,作者[希]迪欧米迪斯·斯宾奈里斯(Diomidis Spinellis),爱飞翔 译,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

第17条:使故障更加突出

使故障显得更加突出一些,可以提升调试工作的效率。为了突出软件的故障,我们可以对软件本身,或是对其输入数据所在的环境进行修改。无论怎样修改,都必须在版本控制系统中进行,而且要在单独的分支上面修改,这样,以后可以轻易地恢复到原来的版本,并且不会在产品代码中引入错误。

有时无论怎么调试,软件都无法像我们期望的那样运作。例如,尽管某一组复杂的条件显然可以得到满足,但数据库里面就是没有出现我们想看到的那条记录。在这种情况下,有一个比较好的办法,是大幅度地改变软件的执行路径,并看其运行结果与你所想的是否相符。如果不符,那说明你思考方向可能有误。

下面这段代码节选自Apache HTTP服务器,它用来处理签名证书的时间戳(signed certificate timestamp,SCT)。服务器有时可能无法应对比当前日期还大的SCT。

《Effective Debugging:软件和系统调试的66个有效方法》——第17条:使故障更加突出
《Effective Debugging:软件和系统调试的66个有效方法》——第17条:使故障更加突出

要想对这种情况进行调试,我们可以临时修改判断条件,使其总是为真(true)。

这样修改之后,我们就可以判断出问题到底是出在修改之前的Boolean条件上面,还是出在测试数据或是用来处理“SCT大于当前日期”的那部分逻辑上面。

还有一些类似的技巧可以考虑,例如,在方法的开头添加return true或return false语句,或是用if(0)把某段代码包裹起来,使得程序跳过这段代码(参见第46条)。

有时我们可能要调试一种或隐或现的效果。在这种情况下,可以临时修改代码,使得这种效果展示得更为明显一些。例如,在制作游戏时,我们想令某个角色在经历了某种事件之后的一分钟之内,具备能力提升的效果。如果在发生了相关事件之后,我们无法看出该角色的能力是否得到了提升,那么可以大幅度地增加能力的提升值,这样就可以更好地进行观察了。例如,在CAD程序里面计算地震对建筑物的影响时,我们想对这种计算逻辑进行调试,那么可以把显示出来的结构位移放大1000倍,以便更好地看出建筑物的移动幅度及移动方向。

如果软件的故障依赖于外部因素,那么可以修改软件的执行环境,令其更为迅速或更为频繁地出现错误(参见第55条),从而凸现该故障。如果软件要处理的是Web请求,那么可以运用Apache JMeter这样的负载测试(load test)或压力测试(stress test)工具,把软件推进到一种行为有可能开始出现异常的地步。如果软件是通过多线程来实现并发的,那么可以增加线程的数量,使其超过计算机的CPU核心数量所能担负的值,以促使程序出现死锁(deadlock)及竞争条件(race condition)等问题。此外,也可以同时运行其他一些耗费内存、CPU、网络或磁盘资源的进程,迫使你所开发的这款软件去和那些进程争夺稀缺资源。其中特别有效的一种做法,是令软件把数据写入容量很小的U盘中,看看它在没有磁盘空间的情况下会表现出什么行为。

最后,还有一种办法也可以帮助你查出较为罕见的数据验证或数据损坏问题,这就是模糊测试(fuzzing)。要想采用这种办法来进行测试,我们可以把随机生成的一些值输入给程序,也可以随机地扰乱程序的输入值,然后看看程序会表现出何种行为。我们的目标,是要找到一种能够令程序偶尔发生故障的数据模式,并采用系统化的方式来提升这种数据模式的出现概率。做到了这一点之后,我们就可以拿这些有问题的数据来调试程序了。如果应用程序在客户的计算机上运行并处理其生产数据时总是发生故障,而在你自己的开发计算机上运行时却不会发生故障,那么这个技巧或许能够帮你找到原因。模糊测试可以通过zzuf这样的工具用来执行。

要点

  • 迫使软件去执行那些可疑的路径。
  • 提升某些效果的幅度,令其变得更加突出,以便于我们进行研究。
  • 对软件加压,迫使它走出能够从容应对负载的那种舒适状态。
  • 在版本管理系统中临时创建一个分支,并把所有的修改都放在这个分支上面来做。
上一篇:实战DeviceIoControl 之四:获取硬盘的详细信息


下一篇:阿里云ACP认证考试细则须知与考题内容学习方法分享