如何定位Obj-C野指针随机Crash(二):让非必现Crash变成必现
发布于 6 个月前 作者 violinxliu 1028 次浏览 来自 技术

本文来自于 腾讯 Bugly,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,非经作者同意,请勿转载。

注:本文主要介绍一种延迟内在释放的技术,继续上一篇提到的 如何提高野指针Crash的概率。另外,本文探讨的环境是在非arc情况下。

只有小概率Crash肿么办?

之前介绍了一种在内存释放后填充0x55使野指针后数据不能访问,从而使某些野指针从不必现Crash变成了必现。然而,我们早就看穿了一切,这个事情不会那么顺利的。

加上上次的代码之后,再试试下面的代码 untitled1.png

依然有大概率不会Crash!难道是我们的实现有问题?我试了一下xcode的Enable Scribble,但一样是大概率不Crash!

其实这就是上一篇文中留下了几个问题之一,如果我们填充0x55后内存又被别的内存覆盖了,最终还是会出现随机Crash。而在真实环境中,这种情况是非常常见的。 我们再梳理一下这个过程:

  1. 我们在即将要释放的填了0x55,之后调用了free真正释放,内存被系统回收。
  2. 这个时候系统随时可能把这片内存给别的代码使用,也就是说我们的0x55被再次写上随机的数据(在这里再强调一下,访问野指针是不会Crash的,只有野指针指向的地址被写上了有问题的数据才会引发Crash)。
  3. 假如释放的内存上又填上了另一个对象的指针,而那个对象也有同样的一个方法,那很可能只是逻辑上有问题,并不会直接Crash,甚至悄无声息地像什么事情都没发生一样。(这个地方可能会发生多种情况,可以参考之上一篇文章中的图)

没有发生Crash可不是好事,因为这种情况如果后续再Crash,问题就非常难查,因为你看到的Crash栈很可能和出错的代码完全没有关联。既然这个问题这么棘手,最好还是和之前一样,让这个Crash提前暴露。

继续提高Crash率

沿着上次的思路,首先,我们要解决的问题就是怎么让系统不再往这片释放的内存上乱放东西。 要控制底层内存管理机制让它不使用这些内存可能很困难。但是,我们变通一下,简单粗暴地,我们干脆就不释放这片内存了。也就是当free被调用的时候我们不真的调用free,而是自己保留着内存,这样系统不知道这片内存已经不需要用了,自然就不会被再次写上别的数据(偷笑)。

为了防止系统内存过快耗尽,还需要额外多做几件事:

  1. 自己保留的内存大于一定值的时候就释放一部分,防止被系统杀死。
  2. 系统内存警告的时候,也要释放一部分内存。

主要代码还是很简单的: untitled2.png

这里需要注意一下:

  1. 在safe_free以及它调用的函数里面尽量不要再用带锁的函数,不然很容易导致死锁。
  2. 加上这个代码之后APP的内存占用会增大不少,拿过来测试可以,但万万不能放在正式的发布版本中
  3. 关于性能问题,我的机器是iPhone5,跑在App里面运行,还算流畅(不同App性能可能会有些不同)。
  4. 可能由于锁的存在,会使cpu线程切换变得频繁,这样多线程的问题Crash率也可能会提升(最近遇到一个多线程引起的Crash很难重现,但我加了这个代码后就变成了必现Crash)

做完这些之后拿到项目中实际验证一下,验证的版本可以是经过测试,且遗留Crash问题已经很少,但还没有对外灰度或发布的版本。 现在来看一下效果: untitled3.png 终于出现了我们熟悉的Crash了!并且,我们做了更多的尝试之后,Crash还是以高概率重现! untitled4.png

但以上代码只是雏形,其实还有很多地方可以优化,大家在试用时可以参考着优化:

  1. 最好是根据机器的情况来决定偷偷保留内存的数量。
  2. 由于内存申请太过频繁,其实我们保留的内存很快就会耗尽,对于大片的内存,可以适当放过,这样可以提高保存指针的数量,防止消耗的内存过多。
  3. 有的APP自己写的都是Obj-C代码,想忽略c、c++对象的话可以过滤掉(会有办法判断的)。
  4. 如果觉得某些Obj-C类有问题,可以只保留指定的类对象,如果数量不是特别大,甚至可以干脆不释放。
  5. ……

总结一下

理论上,机器的内存越大,我们就可以瞒着系统不释放更多内存,野指针Crash的概率也就越大。

如果你觉得内容意犹未尽,如果你想了解更多相关信息,请扫描以下二维码,关注我们的公众账号,可以获取更多技术类干货,还有精彩活动与你分享~

untitled7.png

腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!