一. 前言
最近最近被指派去解决一些线上的崩溃问题,经常遇到野指针导致的崩溃。相对于其他的原因引起的崩溃来说,野指针导致崩溃是最难定位的,这里主要总结了两种思路来定位野指针导致的崩溃。
二. 野指针
1.定义
当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称野指针.
2. 为什么Obj-C野指针的Crash那么多?
一般app版本发布之前都会经过多轮研发自测、测试内测、灰度测试、开放部分客户公测等,按理说很多Crash的场景都应该覆盖到了,但由于野指针的随机性,很经常会使得测试的时候,它是没有问题,等到真正用户使用的时候才有问题,
随机性问题可以大概分为两类:
-
跑不进出错的逻辑,执行不到出错的代码,这种可以提高测试
场景覆盖度来解决。 -
跑进了有问题的逻辑,但是
野指针指向的地址并不一定会导致Crash,这就有点看人品了?
为什么跑进了有问题的逻辑,但还是不一定会导致Crash呢?
3.分析
野指针是指指向一个已删除的对象或未申请访问受限内存区域的指针。本文说的Obj-C野指针,说的是Obj-C对象释放之后指针未置空,导致的野指针(Obj-C里面一般不会出现为初始化对象的常识性错误)。
既然是访问已经释放的对象为什么不是必现Crash呢?
因为dealloc执行后只是告诉系统,这片内存我不用了,而系统并没有就让这片内存不能访问。
现实大概是下面几种可能的情况:
-
对象释放后内存没被改动过,原来的内存保存完好,可能不Crash或者出现逻辑错误(随机Crash)。 -
对象释放后内存没被改动过,但是它自己析构的时候已经删掉某些必要的东西,可能不Crash、Crash在访问依赖的对象比如类成员上、出现逻辑错误(随机Crash)。 -
对象释放后内存被改动过,写上了不可访问的数据,直接就出错了很可能Crash在objc_msgSend上面(必现Crash,常见)。 -
对象释放后内存被改动过,写上了可以访问的数据,可能不Crash、出现逻辑错误、间接访问到不可访问的数据(随机Crash)。 -
对象释放后内存被改动过,写上了可以访问的数据,但是再次访问的时候执行的代码把别的数据写坏了,遇到这种Crash只能哭了(随机Crash,难度大,概率低)!! -
对象释放后再次release(几乎是必现Crash,但也有例外,很常见)。
如图所示:

正是因为野指针有如上多种情况,所以导致crash率一直降不下去。
三. 解决思路
1. 方案一
主要是依据腾讯Bugly工程师:陈其锋的分享得来。
Demo: FJFZombieSnifferDemo
A. 主要思路
-
通过
fishhook替换C函数的free方法为自身方法safe_free,就类似runtime的方法交换。
bool init_safe_free() {
_unfreeQueue = ds_queue_create(MAX_STEAL_MEM_NUM);
orig_free = (void(*)(void*))dlsym(RTLD_DEFAULT, "free");
rebind_symbols((struct rebinding[]){
{"free", (void*)safe_free}}, 1);
return true;
}
-
然后在
safe_free方法中对已经释放变量的内存,填充0x55,使已经释放变量不能访问,从而使某些野指针从不必现Crash变成了必现。
这里之所以填充为0x55是因为Xcode

本文介绍了iOS应用中常见的野指针问题,分析了野指针产生的原因,并提出了两种解决方案:方案一是通过替换消息发送方法进行野指针嗅探;方案二是利用运行时交换方法来定位。这两种方案各有优缺点,适用于不同的项目需求。
最低0.47元/天 解锁文章
1419

被折叠的 条评论
为什么被折叠?



