当程序崩溃发生后,我做了如下工作

Posted yilang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当程序崩溃发生后,我做了如下工作相关的知识,希望对你有一定的参考价值。

这是一个相当简单的错误。使用字节计数而不是字符计数调用了宽字符串函数,从而导致缓冲区溢出。找到问题后,修复方法很简单,只需将sizeof更改为_countof,很容易的。但像这样的BUG浪费时间。由于崩溃,playtest被取消了,而且由于缓冲区溢出破坏了堆栈,因此找到错误代码并非易事。我知道这种类型的错误是可以避免的,我知道还有很多工作要做。

我所做的工作包括:

尽量早点诊断

如果程序在发出错误的宽字符函数调用的函数内部崩溃了,那么找到错误将是微不足道的——代码检查会很快发现它。但是,一旦执行从该函数返回,垃圾堆就模糊了bug的位置,使其调查变得更加棘手。

事实证明,有一个VC++编译器开关可以防止在破坏堆栈后返回。所以,我做的第一件事就是打开开关。这个开关告诉VC++在堆栈上添加一个标志,并在返回之前进行检查。当这个开关打开的时候,溢出的功能被抓住了,找到它花了几秒钟。GS开关是作为一种安全特性,用于防止恶意的缓冲区溢出,但它也可以作为开发人员的生产力工具很好地工作。它确实有一些运行时开销,但这种权衡通常是值得的,尤其是在内部构建上,推荐使用。

技术图片

修改bug

一旦我打开/GS并重新调试了这个bug,找到这个bug就很简单了,所以下一步就是修复它,如前所述。

保护证据

当缓冲区溢出破坏堆栈时,buggy函数返回到一个垃圾地址,这个地址正好在堆中。抹掉bug所在位置的证据已经够糟糕的了,但更糟糕的是,在返回堆中的地址后,会将堆中的数据作为指令执行。这扰乱了寄存器和堆栈,通常会使事情变得混乱。

还有,一个可执行堆?真正地?这是一个首要的安全漏洞。因此,下一个任务是将链接器设置更改为/NXCOMPAT。这将告诉Windows使堆和堆栈不可执行。这大大提高了安全性,还可以简化调试。而且,这个选项没有运行时成本,推荐使用。实际上,这应该被认为是必要的。

技术图片

 

我还打开了我们的发布分支中的/DYNAMICBASE链接器开关,以进一步提高安全性,同时也没有运行时开销。

规避崩溃风险

在这一点上,我已经修复了这个错误,使以后的此类错误更容易调查,并提高了安全性。但还有很多事情要做。原来这种错误很容易犯。当开发人员传递缓冲区和大小时,传递错误大小的方法至少有六种。将来避免这些错误的最好方法是避免传递大小。创建以数组为参数并以100%的精度推断大小的模板函数非常容易。与其写这个:

mywprintf(buffer, _countof(buffer), …); // Verbose and dangerous

你可以写成下面的:

mywprintf_safe(buffer, …); // Compact and safe

它打字少,阅读少,而且保证是正确的。接受数组引用的模板化函数的语法有点粗糙,但您只需要在几个地方正确地使用它。如果有一个原始指针,模板技术就不起作用,但是对于任何其他目标,您应该能够创建一个重载来处理它。手动传递的大小应该很少。因此,我的下一个任务是为所有字符串函数添加模板重写,并鼓励每个人在所有新代码中使用它们,从而使避免再次编写此类错误变得非常简单。

避免过去的风险

虽然safe模板函数可以让我们在将来避免编写这种类型的bug,但它们对现有的数百万行代码却无能为力。可以肯定的是,有更多的尺寸不匹配等着咬我们。所以我在字符串函数中添加了SAL注释,启动了visualstudio的/analyze,并开始编译。到目前为止,这是最大的任务。任何没有运行静态分析的大型代码库都会有很多可检测的bug。缓冲区溢出、逻辑错误、格式字符串不匹配、释放后使用等等。分析了上千个项目,修复了5个主要的机器故障。这是几个月的工作分散了几年,但时间是值得花的。今天它仍在发现新的编码错误。

回到未来

/GS、/NXCOMPAT、/DYNAMICBASE、/analyze及其所有相关工作(加上实际修复bug)花费了大量时间,但绝对值得。大多数这些改变都是微不足道的,有巨大的回报。到目前为止,运行/分析是最大的任务,但和其他聪明的程序员一样,我相信这是无价的。以前经常出现的各种错误——严重的崩溃性错误和疯狂的逻辑错误——现在已经完全绝迹了。通常情况下,您不可能完全消除几十种类型的bug,这样做无疑会提高开发人员的生产率和产品的可靠性。

当然,不再发生的崩溃是不可能的,不可能知道这项工作是否阻止了一次严重的黑天鹅事件。这些好处的无形性使得这种预防性错误修复很难得到认可,所以请记住这一点。

简单的bug不应该总是触发数月的工作,但重要的是要认识到它们应该在什么时候出现。

 

以上是关于当程序崩溃发生后,我做了如下工作的主要内容,如果未能解决你的问题,请参考以下文章

应用程序崩溃后未填充 xCode 设备日志

面试官:为什么应用出现异常会崩溃?

防止升级用户的 CoreData 崩溃

关闭应用程序后解析推送通知崩溃

检测我的Mac应用程序是否崩溃,然后继续正常崩溃

从 Play 商店安装时,Android Cordova 应用程序崩溃