iOS 异常(crash)处理与野指针

异常分类

软件异常(OC异常)

主要来源于 kill() 、 pthread_kill() 两个 API 的调用, 而 iOS 中我们常常遇到的 NSException 未捕获、 abort() 函数调用等,都属于这种情况。比如我们常看到 Crash 堆栈中有 pthead_kill 方法的调用。当一个OC异常被抛出到最外层还没被捕获,程序会强行发送SIGABRT信号中断程序。如果使用try catch捕获此异常,应用不会闪退。

kill() 、 pthread_kill()两个方法分别是向进程、线程发送信号,而不是字面意思直接杀死进程or线程,只不过是因为大部分signal都是杀死线程or进程的。

如下面各类未捕获的NSException,常见的unrecognized selector sendt to instance就属于第一个NSInvalidArgumentException

NSInvalidArgumentException
NSRangeException
NSGenericException
NSInternalInconsistencyException
NSFileHandleOperationException

软件异常 -> UNIX信号

硬件异常(Mach异常)

底层的内核级异常。

例如平常的异常EXC_BAD_ACCESS (SIGSEGV)表示的意思是:Mach层的EXC_BAD_ACCESS异常,在BSD层被转换成SIGSEGV信号发送到出错的线程。

Mach异常最终会经过BSD层会转化成信号,可以通过捕获信号,来捕获 Crash异常 事件。

硬件异常 -> Mach异常 -> UNIX信号

image.png

异常捕获

无论是硬件产生的信号,还是软件产生的信号,都会走到 act_set_astbsd() 进而唤醒收到信号的进程的某一个线程。这个机制就给我们在“自身进程内捕获 Crash” 提供了可能性。就是可以通过拦截 “UNIX信号” 或 “Mach异常” 来捕获崩溃。

  • 软件异常(OC异常)
    NSException异常是比较容易处理的,通过注册 NSUncaughtExceptionHandler捕获异常信息即可
 // register the uncaught exception handler
 NSSetUncaughtExceptionHandler(&handler);
  • 硬件异常(Mach异常)
    通过注册signalHandler来捕获信号。再如EXC_CRASH异常,在BSD层会被转换成SIGABRT信号发送出去。

Mach异常与Signal信号对应

image.png

保持异常发生现场

下面代码是捕获NSException异常

  // 捕获Mach异常
    NSSetUncaughtExceptionHandler(&handleException);
    

handleException回调函数中,可以获取到当前的RunLoop,然后获取该RunLoop中的所有Mode,手动运行一遍。这样就保持达到拦截Crash,保证App不崩溃。

- (void)handleException:(NSException *)exception
{
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
    
    while (YES) {//强制进入死循环
        for (NSString *mode in (__bridge NSArray *)allModes) {
            CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
        }
    }
    
    CFRelease(allModes);
    //解除监听异常
    NSSetUncaughtExceptionHandler(NULL);
}

野指针

当一个指针所指向的对象被释放或者收回,但是该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,这个指针就是野指针。

发生野指针时,App不一定会立马产生闪退,因为因为类的dealloc方法执行后只是告诉系统,这片内存不用了,而系统并没有让这片内存不能访问。此时下次访问前,这块内存还没被覆盖,那使用这个指针还可能是正常的。当然如果这块内存被覆盖了,那就产生闪退。

针对这种问题,一般的优化思路是让dealloc之后,强制覆盖这块内存区域。

Xocde有自带的工具如下


image.png

1、Malloc Scribble ,其官方解释如下:申请内存 alloc 时在内存上填0xAA,释放内存 dealloc 在内存上填 0x55。

2、Zombie Objects,其官方解释如下:一个对象已经解除了它的引用,已经被释放掉,但是此时仍然是可以接受消息,这个对象就叫做Zombie Objects(僵尸对象)。

僵尸原理大概如下,当dealloc方法执行时,动态生成一个僵尸对象类,并修改当前的对象的isa指针指向新生成的僵尸对象类,这个新的类中只有一个isa指针,里面没有其他的属性和方法,所以不能响应任何事件,所以在向这个僵尸对象发送消息时,就会必须crash。

当然上述两种方法都是要借助Xcode调试才能使用,如果是测试或者线上的环境,就难以实现,特别是线上的crash,野指针发生不一定crash,等发生crash时,堆栈信息参考性不准确。

定位野指针

主要思路是通过Facebook的fishhook库,hook系统的free函数,在释放的时候覆盖为0x55。

1、通过fishhook替换C函数的free方法为自定义的safe_free。

2、在safe_free方法中对已经释放变量的内存,填充0x55,使已经释放变量不能访问,从而使某些野指针的crash从不必现安变成必现。

参考
https://juejin.cn/post/6968700344050122766#heading-5
https://developer.aliyun.com/article/766088

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258